RE: MSDOSFS patch of dirty flag (Darwin Import)

From: Jun Su <csujun_at_yahoo.com>
Date: Fri, 18 Jul 2003 19:39:40 -0700 (PDT)
I can not make my MTA work.....
================================
To: FreeBSD-gnats-submit_at_freebsd.org
From: Jun Su <csujun_at_263.net>
Reply-To: Jun Su <csujun_at_263.net>
Cc:
X-send-pr-version: 3.113
X-GNATS-Notify:


>Submitter-Id:	current-users
>Originator:	Jun Su
>Organization:	none
>Confidential:	no <FreeBSD PRs are public data>
>Synopsis:	[PATCH] MSDOSFS dirty path (importing from
Darwin)
>Severity:	non-critical
>Priority:	medium
>Category:	kern
>Class:		change-request
>Release:	FreeBSD 5.1-CURRENT i386
>Environment:
System: FreeBSD junsufr.gwbn.sh.cn 5.1-CURRENT FreeBSD
5.1-CURRENT #1: Thu Jul 17 18:01:10 CST 2003
root_at_junsufr.gwbn.sh.cn:/usr/obj/usr/src/sys/VAIO i386

>Description:
	A TODO item in the 5.2 Release Must Resolve List.
>How-To-Repeat:
>Fix:

diff -u /usr/src/sys/fs/msdosfs.orig/fat.h
msdosfs/fat.h
--- /usr/src/sys/fs/msdosfs.orig/fat.h	Tue Mar 19
22:20:10 2002
+++ msdosfs/fat.h	Mon Jul 14 21:02:10 2003
_at__at_ -99,5 +99,6 _at__at_
 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 */
Only in msdosfs: fat.h.orig
diff -u /usr/src/sys/fs/msdosfs.orig/msdosfs_fat.c
msdosfs/msdosfs_fat.c
--- /usr/src/sys/fs/msdosfs.orig/msdosfs_fat.c	Tue Mar
 4 00:04:42 2003
+++ msdosfs/msdosfs_fat.c	Mon Jul 14 21:02:10 2003
_at__at_ -1106,3 +1106,70 _at__at_
 
 	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);
+}
Only in msdosfs: msdosfs_fat.c.orig
diff -u /usr/src/sys/fs/msdosfs.orig/msdosfs_vfsops.c
msdosfs/msdosfs_vfsops.c
--- /usr/src/sys/fs/msdosfs.orig/msdosfs_vfsops.c	Sun
Jun 29 03:05:59 2003
+++ msdosfs/msdosfs_vfsops.c	Mon Jul 14 21:02:11 2003
_at__at_ -203,6 +203,11 _at__at_
 				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 */
_at__at_ -603,8 +608,13 _at__at_
 	 */
 	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;
_at__at_ -651,6 +661,14 _at__at_
 		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;
diff -u /usr/src/sbin/fsck_msdosfs.orig/check.c
fsck_msdosfs/check.c
--- /usr/src/sbin/fsck_msdosfs.orig/check.c	Wed Aug 21
18:10:33 2002
+++ fsck_msdosfs/check.c	Sun Jul 13 22:00:24 2003
_at__at_ -85,6 +85,13 _at__at_
 		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");
_at__at_ -190,5 +197,51 _at__at_
 	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;
 }
diff -u /usr/src/sbin/fsck_msdosfs.orig/ext.h
fsck_msdosfs/ext.h
--- /usr/src/sbin/fsck_msdosfs.orig/ext.h	Wed Aug 21
18:10:33 2002
+++ fsck_msdosfs/ext.h	Sun Jul 13 17:39:14 2003
_at__at_ -48,6 +48,7 _at__at_
 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
*/
 
_at__at_ -85,6 +86,12 _at__at_
  * 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
diff -u /usr/src/sbin/fsck_msdosfs.orig/main.c
fsck_msdosfs/main.c
--- /usr/src/sbin/fsck_msdosfs.orig/main.c	Tue Aug 27
00:49:22 2002
+++ fsck_msdosfs/main.c	Sun Jul 13 17:39:14 2003
_at__at_ -53,6 +53,7 _at__at_
 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;
 
_at__at_ -67,14 +68,12 _at__at_
 {
 	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 */


__________________________________
Do you Yahoo!?
SBC Yahoo! DSL - Now only $29.95 per month!
http://sbc.yahoo.com
Received on Fri Jul 18 2003 - 17:39:41 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:37:15 UTC