Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 22 Aug 2003 03:14:12 -0400 (EDT)
From:      Jun Su <junsu@m-net.arbornet.org>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   kern/55861: [PATCH] MSDOSFS patch for dirty flag and lockf support
Message-ID:  <200308220714.h7M7EC49008356@m-net.arbornet.org>
Resent-Message-ID: <200308220720.h7M7KD3u075367@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>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:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200308220714.h7M7EC49008356>