Make msdosfs support the dirty flag in FAT16 and FAT32.
Enable lockf support. PR: 55861 Submitted by: Jun Su <junsu@m-net.arbornet.org> (original version) Reviewed by: make universe
This commit is contained in:
parent
7ca70c753b
commit
cede1f563c
@ -84,6 +84,13 @@ checkfilesys(const char *fname)
|
||||
return 8;
|
||||
}
|
||||
|
||||
if (checkdirty(dosfs, &boot) && !force) {
|
||||
if (preen) printf("%s: ", fname);
|
||||
printf("FILESYSTEM CLEAN; SKIPPING CHECKS\n");
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!preen) {
|
||||
if (boot.ValidFat < 0)
|
||||
printf("** Phase 1 - Read and Compare FATs\n");
|
||||
@ -191,3 +198,48 @@ checkfilesys(const char *fname)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int checkdirty(int fs, struct bootblock *boot)
|
||||
{
|
||||
off_t off;
|
||||
u_char *buffer;
|
||||
int ret = 0;
|
||||
|
||||
if (boot->ClustMask == CLUST12_MASK)
|
||||
return 0;
|
||||
|
||||
off = boot->ResSectors;
|
||||
off *= boot->BytesPerSec;
|
||||
|
||||
buffer = malloc(boot->BytesPerSec);
|
||||
if (buffer == NULL) {
|
||||
perror("No space for FAT");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lseek(fs, off, SEEK_SET) != off) {
|
||||
perror("Unable to read FAT");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (read(fs, buffer, boot->BytesPerSec)
|
||||
!= boot->BytesPerSec) {
|
||||
perror("Unable to read FAT");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (buffer[0] == boot->Media && buffer[1] == 0xff
|
||||
&& buffer[2] == 0xff
|
||||
&& ((boot->ClustMask == CLUST16_MASK && buffer[3] == 0x7f)
|
||||
|| (boot->ClustMask == CLUST32_MASK
|
||||
&& buffer[3] == 0x0f && buffer[4] == 0xff
|
||||
&& buffer[5] == 0xff && buffer[6] == 0xff
|
||||
&& buffer[7] == 0x07)))
|
||||
ret = 0;
|
||||
else
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ extern int alwaysno; /* assume "no" for all questions */
|
||||
extern int alwaysyes; /* assume "yes" for all questions */
|
||||
extern int preen; /* we are preening */
|
||||
extern int rdonly; /* device is opened read only (supersedes above) */
|
||||
extern int force;
|
||||
|
||||
extern struct dosDirEntry *rootDir;
|
||||
|
||||
@ -84,6 +85,12 @@ int readboot(int, struct bootblock *);
|
||||
*/
|
||||
int writefsinfo(int, struct bootblock *);
|
||||
|
||||
/*
|
||||
* Check the dirty flag. If clean return 1, otherwise return 0.
|
||||
* If it is FAT12, return 0 always.
|
||||
*/
|
||||
int checkdirty(int, struct bootblock *);
|
||||
|
||||
/*
|
||||
* Read one of the FAT copies and return a pointer to the new
|
||||
* allocated array holding our description of it.
|
||||
|
@ -88,11 +88,9 @@ immediately in foreground, or if its cleaning can be deferred to background.
|
||||
FAT (MS-DOS) file systems must always be cleaned in the foreground.
|
||||
A non-zero exit code is always returned for this option.
|
||||
.It Fl f
|
||||
This option is ignored by
|
||||
.Nm ,
|
||||
and is present only for compatibility with programs that
|
||||
check other file system types for consistency, such as
|
||||
.Xr fsck_ffs 8 .
|
||||
Force
|
||||
.Nm
|
||||
to check 'clean' file systems when preening.
|
||||
.It Fl n
|
||||
Causes
|
||||
.Nm
|
||||
|
@ -53,6 +53,7 @@ int alwaysno; /* assume "no" for all questions */
|
||||
int alwaysyes; /* assume "yes" for all questions */
|
||||
int preen; /* set when preening */
|
||||
int rdonly; /* device is opened read only (supersedes above) */
|
||||
int force; /* force check even the fs is clean */
|
||||
|
||||
static void usage(void) __dead2;
|
||||
|
||||
@ -67,14 +68,12 @@ main(int argc, char **argv)
|
||||
{
|
||||
int ret = 0, erg;
|
||||
int ch;
|
||||
|
||||
|
||||
force = 0;
|
||||
while ((ch = getopt(argc, argv, "fFnpy")) != -1) {
|
||||
switch (ch) {
|
||||
case 'f':
|
||||
/*
|
||||
* We are always forced, since we don't
|
||||
* have a clean flag
|
||||
*/
|
||||
force = 1;
|
||||
break;
|
||||
case 'F':
|
||||
/* We can never run in background */
|
||||
|
@ -160,6 +160,7 @@ struct denode {
|
||||
u_long de_FileSize; /* size of file in bytes */
|
||||
struct fatcache de_fc[FC_SIZE]; /* fat cache */
|
||||
u_quad_t de_modrev; /* Revision level for lease. */
|
||||
struct lockf *de_lockf; /* lockf */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -99,5 +99,6 @@ int fatentry(int function, struct msdosfsmount *pmp, u_long cluster, u_long *old
|
||||
int freeclusterchain(struct msdosfsmount *pmp, u_long startchain);
|
||||
int extendfile(struct denode *dep, u_long count, struct buf **bpp, u_long *ncp, int flags);
|
||||
void fc_purge(struct denode *dep, u_int frcn);
|
||||
int markvoldirty(struct msdosfsmount *pmp, int dirty);
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
@ -1106,3 +1106,70 @@ extendfile(dep, count, bpp, ncp, flags)
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* [2753891]
|
||||
* Routine to mark a FAT16 or FAT32 volume as "clean" or "dirty" by manipulating the upper bit
|
||||
* of the FAT entry for cluster 1. Note that this bit is not defined for FAT12 volumes, which
|
||||
* are always assumed to be dirty.
|
||||
*
|
||||
* The fatentry() routine only works on cluster numbers that a file could occupy, so it won't
|
||||
* manipulate the entry for cluster 1. So we have to do it here. The code is ripped from
|
||||
* fatentry(), and tailored for cluster 1.
|
||||
*
|
||||
* Inputs:
|
||||
* pmp The MS-DOS volume to mark
|
||||
* dirty Non-zero if the volume should be marked dirty; zero if it should be marked clean.
|
||||
*
|
||||
* Result:
|
||||
* 0 Success
|
||||
* EROFS Volume is read-only
|
||||
* ? (other errors from called routines)
|
||||
*/
|
||||
int markvoldirty(struct msdosfsmount *pmp, int dirty)
|
||||
{
|
||||
int error;
|
||||
u_long bn, bo, bsize, byteoffset;
|
||||
u_long fatval;
|
||||
struct buf *bp;
|
||||
|
||||
/* FAT12 does not support a "clean" bit, so don't do anything */
|
||||
if (FAT12(pmp))
|
||||
return 0;
|
||||
|
||||
/* Can't change the bit on a read-only filesystem */
|
||||
if (pmp->pm_flags & MSDOSFSMNT_RONLY)
|
||||
return EROFS;
|
||||
|
||||
/* Fetch the block containing the FAT entry */
|
||||
byteoffset = FATOFS(pmp, 1); /* Find the location of cluster 1 */
|
||||
fatblock(pmp, byteoffset, &bn, &bsize, &bo);
|
||||
|
||||
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Get the current value of the FAT entry and set/clear the high bit */
|
||||
if (FAT32(pmp)) {
|
||||
/* FAT32 uses bit 27 */
|
||||
fatval = getulong(&bp->b_data[bo]);
|
||||
if (dirty)
|
||||
fatval &= 0xF7FFFFFF; /* dirty means clear the "clean" bit */
|
||||
else
|
||||
fatval |= 0x08000000; /* clean means set the "clean" bit */
|
||||
putulong(&bp->b_data[bo], fatval);
|
||||
}
|
||||
else {
|
||||
/* Must be FAT16; use bit 15 */
|
||||
fatval = getushort(&bp->b_data[bo]);
|
||||
if (dirty)
|
||||
fatval &= 0x7FFF; /* dirty means clear the "clean" bit */
|
||||
else
|
||||
fatval |= 0x8000; /* clean means set the "clean" bit */
|
||||
putushort(&bp->b_data[bo], fatval);
|
||||
}
|
||||
|
||||
/* Write out the modified FAT block immediately */
|
||||
return bwrite(bp);
|
||||
}
|
||||
|
@ -209,6 +209,11 @@ msdosfs_mount(mp, path, data, ndp, td)
|
||||
VOP_UNLOCK(devvp, 0, td);
|
||||
}
|
||||
pmp->pm_flags &= ~MSDOSFSMNT_RONLY;
|
||||
|
||||
/* [2753891] Now that the volume is modifiable, mark it dirty */
|
||||
error = markvoldirty(pmp, 1);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
if (args.fspec == 0) {
|
||||
#ifdef __notyet__ /* doesn't work correctly with current mountd XXX */
|
||||
@ -609,8 +614,12 @@ mountmsdosfs(devvp, mp, td, argp)
|
||||
*/
|
||||
if (ronly)
|
||||
pmp->pm_flags |= MSDOSFSMNT_RONLY;
|
||||
else
|
||||
else {
|
||||
/* [2753891] Mark the volume dirty while it is mounted read/write */
|
||||
if ((error = markvoldirty(pmp, 1)) != 0)
|
||||
goto error_exit;
|
||||
pmp->pm_fmod = 1;
|
||||
}
|
||||
mp->mnt_data = (qaddr_t) pmp;
|
||||
mp->mnt_stat.f_fsid.val[0] = dev2udev(dev);
|
||||
mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
|
||||
@ -667,6 +676,13 @@ msdosfs_unmount(mp, mntflags, td)
|
||||
msdosfs_iconv->close(pmp->pm_u2d);
|
||||
}
|
||||
pmp->pm_devvp->v_rdev->si_mountpoint = NULL;
|
||||
|
||||
/* [2753891] If the volume was mounted read/write, mark it clean now */
|
||||
if ((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0) {
|
||||
error = markvoldirty(pmp, 0);
|
||||
if (error && !(flags & FORCECLOSE))
|
||||
return (error);
|
||||
}
|
||||
#ifdef MSDOSFS_DEBUG
|
||||
{
|
||||
struct vnode *vp = pmp->pm_devvp;
|
||||
|
@ -63,6 +63,7 @@
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/dirent.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/lockf.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_extern.h>
|
||||
@ -101,6 +102,7 @@ static int msdosfs_bmap(struct vop_bmap_args *);
|
||||
static int msdosfs_strategy(struct vop_strategy_args *);
|
||||
static int msdosfs_print(struct vop_print_args *);
|
||||
static int msdosfs_pathconf(struct vop_pathconf_args *ap);
|
||||
static int msdosfs_advlock(struct vop_advlock_args *);
|
||||
|
||||
/*
|
||||
* Some general notes:
|
||||
@ -1836,6 +1838,23 @@ msdosfs_pathconf(ap)
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* Advisory record locking support
|
||||
*/
|
||||
static int
|
||||
msdosfs_advlock(ap)
|
||||
struct vop_advlock_args /* {
|
||||
struct vnode *a_vp;
|
||||
u_char a_id;
|
||||
int a_op;
|
||||
struct flock *a_fl;
|
||||
int a_flags;
|
||||
} */ *ap;
|
||||
{
|
||||
struct denode *ip = VTODE(ap->a_vp);
|
||||
|
||||
return (lf_advlock(ap, &(ip->de_lockf), ip->de_FileSize));
|
||||
}
|
||||
|
||||
/* Global vfs data structures for msdosfs */
|
||||
vop_t **msdosfs_vnodeop_p;
|
||||
@ -1865,6 +1884,7 @@ static struct vnodeopv_entry_desc msdosfs_vnodeop_entries[] = {
|
||||
{ &vop_strategy_desc, (vop_t *) msdosfs_strategy },
|
||||
{ &vop_symlink_desc, (vop_t *) msdosfs_symlink },
|
||||
{ &vop_write_desc, (vop_t *) msdosfs_write },
|
||||
{ &vop_advlock_desc, (vop_t *) msdosfs_advlock },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
static struct vnodeopv_desc msdosfs_vnodeop_opv_desc =
|
||||
|
Loading…
Reference in New Issue
Block a user