kern/55861: [PATCH] MSDOSFS patch for dirty flag and lockf support
Jun Su
junsu at m-net.arbornet.org
Fri Aug 22 00:20:16 PDT 2003
>Number: 55861
>Category: kern
>Synopsis: [PATCH] MSDOSFS patch for dirty flag and lockf support
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: update
>Submitter-Id: current-users
>Arrival-Date: Fri Aug 22 00:20:13 PDT 2003
>Closed-Date:
>Last-Modified:
>Originator: Jun Su
>Release: FreeBSD 5.1-current i386
>Organization:
NONE
>Environment:
>Description:
The patch is from DARWIN msdosfs. It patch msdosfs and fsck_msdosfs.
The patch make the msdosfs support dirty flag in FAT16 and FAT32.
I also enabled lockf support.
>How-To-Repeat:
>Fix:
[msdosfs.diff]
Index: sys/fs/msdosfs/denode.h
===================================================================
RCS file: /home/ncvs/src/sys/fs/msdosfs/denode.h,v
retrieving revision 1.25
diff -u -r1.25 denode.h
--- sys/fs/msdosfs/denode.h 24 Jun 2003 22:11:20 -0000 1.25
+++ sys/fs/msdosfs/denode.h 13 Aug 2003 07:07:40 -0000
@@ -160,6 +160,7 @@
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 */
};
/*
Index: sys/fs/msdosfs/fat.h
===================================================================
RCS file: /home/ncvs/src/sys/fs/msdosfs/fat.h,v
retrieving revision 1.11
diff -u -r1.11 fat.h
--- sys/fs/msdosfs/fat.h 19 Mar 2002 22:20:10 -0000 1.11
+++ sys/fs/msdosfs/fat.h 13 Aug 2003 07:07:40 -0000
@@ -99,5 +99,6 @@
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 */
Index: sys/fs/msdosfs/msdosfs_fat.c
===================================================================
RCS file: /home/ncvs/src/sys/fs/msdosfs/msdosfs_fat.c,v
retrieving revision 1.32
diff -u -r1.32 msdosfs_fat.c
--- sys/fs/msdosfs/msdosfs_fat.c 4 Mar 2003 00:04:42 -0000 1.32
+++ sys/fs/msdosfs/msdosfs_fat.c 13 Aug 2003 07:07:48 -0000
@@ -1106,3 +1106,70 @@
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);
+}
Index: sys/fs/msdosfs/msdosfs_vfsops.c
===================================================================
RCS file: /home/ncvs/src/sys/fs/msdosfs/msdosfs_vfsops.c,v
retrieving revision 1.105
diff -u -r1.105 msdosfs_vfsops.c
--- sys/fs/msdosfs/msdosfs_vfsops.c 12 Aug 2003 20:06:55 -0000 1.105
+++ sys/fs/msdosfs/msdosfs_vfsops.c 13 Aug 2003 07:07:53 -0000
@@ -204,6 +204,11 @@
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 */
@@ -604,8 +609,12 @@
*/
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;
@@ -652,6 +661,13 @@
return error;
pmp = VFSTOMSDOSFS(mp);
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;
Index: sys/fs/msdosfs/msdosfs_vnops.c
===================================================================
RCS file: /home/ncvs/src/sys/fs/msdosfs/msdosfs_vnops.c,v
retrieving revision 1.140
diff -u -r1.140 msdosfs_vnops.c
--- sys/fs/msdosfs/msdosfs_vnops.c 12 Aug 2003 20:06:55 -0000 1.140
+++ sys/fs/msdosfs/msdosfs_vnops.c 13 Aug 2003 07:08:04 -0000
@@ -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_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 @@
/* NOTREACHED */
}
+/*
+ * Advisory record locking support
+ */
+static int
+msdosfs_advlock(ap)
+ struct vop_advlock_args /* {
+ struct vnode *a_vp;
+ caddr_t 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 @@
{ &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 =
[fsck_msdosfs]
Index: sbin/fsck_msdosfs/check.c
===================================================================
RCS file: /home/ncvs/src/sbin/fsck_msdosfs/check.c,v
retrieving revision 1.3
diff -u -r1.3 check.c
--- sbin/fsck_msdosfs/check.c 21 Aug 2002 18:10:33 -0000 1.3
+++ sbin/fsck_msdosfs/check.c 13 Aug 2003 07:12:10 -0000
@@ -85,6 +85,13 @@
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");
@@ -190,5 +197,51 @@
if (mod & (FSFATMOD|FSDIRMOD))
pwarn("\n***** FILE SYSTEM WAS MODIFIED *****\n");
+ return ret;
+}
+
+int checkdirty(int fs, struct bootblock *boot)
+{
+ off_t off;
+ u_char *buffer;
+ u_long dirtyflag;
+ 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;
}
Index: sbin/fsck_msdosfs/ext.h
===================================================================
RCS file: /home/ncvs/src/sbin/fsck_msdosfs/ext.h,v
retrieving revision 1.4
diff -u -r1.4 ext.h
--- sbin/fsck_msdosfs/ext.h 21 Aug 2002 18:10:33 -0000 1.4
+++ sbin/fsck_msdosfs/ext.h 13 Aug 2003 07:12:10 -0000
@@ -48,6 +48,7 @@
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 char *fname; /* file system currently checked */
@@ -85,6 +86,12 @@
* Correct the FSInfo block.
*/
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
Index: sbin/fsck_msdosfs/fsck_msdosfs.8
===================================================================
RCS file: /home/ncvs/src/sbin/fsck_msdosfs/fsck_msdosfs.8,v
retrieving revision 1.9
diff -u -r1.9 fsck_msdosfs.8
--- sbin/fsck_msdosfs/fsck_msdosfs.8 8 Jun 2003 12:53:07 -0000 1.9
+++ sbin/fsck_msdosfs/fsck_msdosfs.8 13 Aug 2003 07:12:13 -0000
@@ -88,11 +88,9 @@
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
Index: sbin/fsck_msdosfs/main.c
===================================================================
RCS file: /home/ncvs/src/sbin/fsck_msdosfs/main.c,v
retrieving revision 1.8
diff -u -r1.8 main.c
--- sbin/fsck_msdosfs/main.c 27 Aug 2002 00:49:22 -0000 1.8
+++ sbin/fsck_msdosfs/main.c 13 Aug 2003 07:12:13 -0000
@@ -53,6 +53,7 @@
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 @@
{
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 */
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list