From owner-freebsd-bugs@FreeBSD.ORG Fri Aug 22 00:20:16 2003 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 445F716A4BF for ; Fri, 22 Aug 2003 00:20:16 -0700 (PDT) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 21B7743FE5 for ; Fri, 22 Aug 2003 00:20:14 -0700 (PDT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.12.9/8.12.9) with ESMTP id h7M7KDUp075368 for ; Fri, 22 Aug 2003 00:20:13 -0700 (PDT) (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.12.9/8.12.9/Submit) id h7M7KD3u075367; Fri, 22 Aug 2003 00:20:13 -0700 (PDT) Resent-Date: Fri, 22 Aug 2003 00:20:13 -0700 (PDT) Resent-Message-Id: <200308220720.h7M7KD3u075367@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Jun Su Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 9DD6416A4BF for ; Fri, 22 Aug 2003 00:14:02 -0700 (PDT) Received: from arbornet.org (m-net.arbornet.org [209.142.209.161]) by mx1.FreeBSD.org (Postfix) with ESMTP id E767A43FB1 for ; Fri, 22 Aug 2003 00:13:58 -0700 (PDT) (envelope-from junsu@m-net.arbornet.org) Received: from m-net.arbornet.org (localhost [127.0.0.1]) by arbornet.org (8.12.3p2/8.11.2) with ESMTP id h7M7ECCU008357 for ; Fri, 22 Aug 2003 03:14:12 -0400 (EDT) (envelope-from junsu@m-net.arbornet.org) Received: (from junsu@localhost) by m-net.arbornet.org (8.12.3p2/8.12.3/Submit) id h7M7EC49008356; Fri, 22 Aug 2003 03:14:12 -0400 (EDT) Message-Id: <200308220714.h7M7EC49008356@m-net.arbornet.org> Date: Fri, 22 Aug 2003 03:14:12 -0400 (EDT) From: Jun Su To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Subject: kern/55861: [PATCH] MSDOSFS patch for dirty flag and lockf support X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list Reply-To: Jun Su List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 22 Aug 2003 07:20:16 -0000 >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 #include #include +#include #include #include @@ -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: