]> Zhao Yanbai Git Server - minix.git/commitdiff
mfs: clean flag
authorBen Gras <ben@minix3.org>
Thu, 22 Dec 2011 00:29:27 +0000 (01:29 +0100)
committerBen Gras <ben@minix3.org>
Thu, 22 Dec 2011 15:53:32 +0000 (16:53 +0100)
     . also implement now-possible fsck -p option
     . allows unconditional fsck -p invocation at startup,
       only checking each filesystem if not marked clean
     . mounting unclean is allowed but is forced readonly
     . updating the superblock while mounted is now not
       allowed by mfs - must be done (e.g. by fsck.mfs)
       on an unmounted fs
. clean flag is unset by mfs on mounting, and set by
  mfs on clean unmounting (if clean flag was set at
  mount time)

Signed-off-by: Ben Gras <ben@minix3.org>
13 files changed:
commands/fsck.mfs/fsck.c
commands/mkfs.mfs/mkfs.c
drivers/ramdisk/Makefile
drivers/ramdisk/proto
drivers/ramdisk/rc
etc/Makefile
etc/rc.subr.minix
servers/mfs/cache.c
servers/mfs/mount.c
servers/mfs/proto.h
servers/mfs/read.c
servers/mfs/super.c
servers/mfs/super.h

index 5f26a22bfd8cce6a5e04668639f62ac335535b78..852a6fdeaa40a5679794aa9dd8d1cf863285e66f 100644 (file)
@@ -146,7 +146,8 @@ int nfreeinode, nregular, ndirectory, nblkspec, ncharspec, nbadinode;
 int nsock, npipe, nsyml, ztype[NLEVEL];
 long nfreezone;
 
-int repair, automatic, listing, listsuper;     /* flags */
+int repair, notrepaired = 0, automatic, listing, listsuper;    /* flags */
+int preen = 0, markdirty = 0;
 int firstlist;                 /* has the listing header been printed? */
 unsigned part_offset;          /* sector offset for this partition */
 char answer[] = "Answer questions with y or n.  Then hit RETURN";
@@ -172,7 +173,9 @@ _PROTOTYPE(void lpr, (char *fmt, long cnt, char *s, char *p));
 _PROTOTYPE(bit_nr getnumber, (char *s));
 _PROTOTYPE(char **getlist, (char ***argv, char *type));
 _PROTOTYPE(void lsuper, (void));
-_PROTOTYPE(void getsuper, (void));
+#define SUPER_GET      0
+#define SUPER_PUT      1
+_PROTOTYPE(void rw_super, (int mode));
 _PROTOTYPE(void chksuper, (void));
 _PROTOTYPE(void lsi, (char **clist));
 _PROTOTYPE(bitchunk_t *allocbitmap, (int nblk));
@@ -251,6 +254,7 @@ char *question;
 {
   register int c, answerchar;
   static int note = 0;
+  int yes;
 
   if (!repair) {
        printf("\n");
@@ -266,7 +270,9 @@ char *question;
   if ((c = answerchar = getchar()) == 'q' || c == 'Q') exit(1);
   if(c == 'A') { automatic = 1; c = 'y'; }
   while (!eoln(c)) c = getchar();
-  return !(answerchar == 'n' || answerchar == 'N');
+  yes = !(answerchar == 'n' || answerchar == 'N');
+  if(!yes) notrepaired = 1;
+  return yes;
 }
 
 /* Convert string to integer.  Representation is octal. */
@@ -373,7 +379,8 @@ int nlcr;
 /* Open the device.  */
 void devopen()
 {
-  if ((dev = open(fsck_device, repair ? O_RDWR : O_RDONLY)) < 0) {
+  if ((dev = open(fsck_device,
+    (repair || markdirty) ? O_RDWR : O_RDONLY)) < 0) {
        perror(fsck_device);
        fatal("couldn't open device to fsck");
   }
@@ -540,17 +547,26 @@ void lsuper()
                devwrite(0, OFFSET_SUPER_BLOCK, (char *) &sb, sizeof(sb));
                return;
        }
+       printf("flags         = ");
+       if(sb.s_flags & MFSFLAG_CLEAN) printf("CLEAN "); else printf("DIRTY ");
+       printf("\n");
   } while (yes("Do you want to try again"));
   if (repair) exit(0);
 }
 
 /* Get the super block from either disk or user.  Do some initial checks. */
-void getsuper()
+void rw_super(int put)
 {
   if(lseek(dev, OFFSET_SUPER_BLOCK, SEEK_SET) < 0) {
        perror("lseek");
        fatal("couldn't seek to super block.");
   }
+  if(put == SUPER_PUT)  {
+    if(write(dev, &sb, sizeof(sb)) != sizeof(sb)) {
+       fatal("couldn't write super block.");
+    }
+    return;
+  }
   if(read(dev, &sb, sizeof(sb)) != sizeof(sb)) {
        fatal("couldn't read super block.");
   }
@@ -628,6 +644,10 @@ void chksuper()
        printf("warning: expected max size to be %ld ", maxsize);
        printf("instead of %ld\n", sb.s_max_size);
   }
+
+  if(sb.s_flags & MFSFLAG_MANDATORY_MASK) {
+       fatal("unsupported feature bits - newer fsck needed");
+  }
 }
 
 int inoblock(int inn)
@@ -795,7 +815,9 @@ char *type;
   int w = nblk * WORDS_PER_BLOCK;
   bit_nr phys = 0;
 
-  printf("Checking %s map\n", type);
+  printf("Checking %s map. ", type);
+  if(!preen) printf("\n");
+  fflush(stdout);
   loadbitmap(dmap, blkno, nblk);
   do {
        if (*p != *q) chkword(*p, *q, bit, type, &nerr, &report, phys);
@@ -817,7 +839,9 @@ void chkilist()
   register ino_t ino = 1;
   mode_t mode;
 
-  printf("Checking inode list\n");
+  printf("Checking inode list. ");
+  if(!preen) printf("\n");
+  fflush(stdout);
   do
        if (!bitset(imap, (bit_nr) ino)) {
                devread(inoblock(ino), inooff(ino), (char *) &mode,
@@ -829,7 +853,7 @@ void chkilist()
                }
        }
   while (++ino <= sb.s_ninodes && ino != 0);
-  printf("\n");
+  if(!preen) printf("\n");
 }
 
 /* Allocate an array to maintain the inode reference counts in. */
@@ -1471,6 +1495,12 @@ void chktree()
 /* Print the totals of all the objects found. */
 void printtotal()
 {
+  if(preen) {
+       printf("%d files, %d directories, %d free inodes, %d free zones\n",
+               nregular, ndirectory, nfreeinode, nfreezone);
+       return;
+  }
+
   printf("blocksize = %5d        ", block_size);
   printf("zonesize  = %5d\n", ZONE_SIZE);
   printf("\n");
@@ -1506,7 +1536,7 @@ char *f, **clist, **ilist, **zlist;
 
   devopen();
 
-  getsuper();
+  rw_super(SUPER_GET);
 
   if(block_size < _MIN_BLOCK_SIZE)
        fatal("funny block size");
@@ -1517,6 +1547,25 @@ char *f, **clist, **ilist, **zlist;
 
   chksuper();
 
+  if(markdirty) {
+       if(sb.s_flags & MFSFLAG_CLEAN) {
+               sb.s_flags &= ~MFSFLAG_CLEAN;
+               rw_super(SUPER_PUT);
+               printf("\n----- FILE SYSTEM MARKED DIRTY -----\n\n");
+       } else {
+               printf("Filesystem is already dirty.\n");
+       }
+  }
+
+  /* If preening, skip fsck if clean flag is on. */
+  if(preen) {
+       if(sb.s_flags & MFSFLAG_CLEAN) {
+               printf("%s: clean\n", f);
+               return;
+       } 
+       printf("%s: dirty, performing fsck\n", f);
+  }
+
   lsi(clist);
 
   getbitmaps();
@@ -1530,13 +1579,29 @@ char *f, **clist, **ilist, **zlist;
   chkcount();
   chkmap(imap, spec_imap, (bit_nr) 0, BLK_IMAP, N_IMAP, "inode");
   chkilist();
+  if(preen) printf("\n");
   printtotal();
 
   putbitmaps();
   freecount();
-  devclose();
 
-  if (changed) printf("----- FILE SYSTEM HAS BEEN MODIFIED -----\n\n");
+  if (changed) printf("\n----- FILE SYSTEM HAS BEEN MODIFIED -----\n\n");
+
+  /* If we were told to repair the FS, and the user never stopped us from
+   * doing it, and the FS wasn't marked clean, we can mark the FS as clean.
+   */
+  if(repair && !(sb.s_flags & MFSFLAG_CLEAN)) {
+       if(notrepaired) {
+               printf("\n----- FILE SYSTEM STILL DIRTY -----\n\n");
+       } else {
+               sync(); /* update FS on disk before clean flag */
+               sb.s_flags |= MFSFLAG_CLEAN;
+               rw_super(SUPER_PUT);
+               printf("\n----- FILE SYSTEM MARKED CLEAN -----\n\n");
+       }
+  }
+
+  devclose();
 }
 
 int main(argc, argv)
@@ -1557,8 +1622,9 @@ char **argv;
   prog = *argv++;
   while ((arg = *argv++) != 0)
        if (arg[0] == '-' && arg[1] != 0 && arg[2] == 0) switch (arg[1]) {
+                   case 'd':   markdirty = 1;  break;
+                   case 'p':   preen = repair = automatic = 1; break;
                    case 'y':
-                   case 'p':
                    case 'a':   automatic ^= 1; break;
                    case 'c':
                        clist = getlist(&argv, "inode");
@@ -1584,7 +1650,7 @@ char **argv;
                devgiven = 1;
        }
   if (!devgiven) {
-       printf("Usage: fsck [-yfpacilrsz] file\n");
+       printf("Usage: fsck [-dyfpacilrsz] file\n");
        exit(1);
   }
   return(0);
index 8237c4bed6a3c5901711a6ed7343aaa4d5e36736..750aa2e241cfd1cc5cfb0d2147c7536eaf72299f 100644 (file)
@@ -388,21 +388,23 @@ char *device;
   unsigned int rem;
   u64_t resize;
 
+
   if ((fd = open(device, O_RDONLY)) == -1) {
-       if (errno != ENOENT)
-               perror("sizeup open");
-       return 0;
+       if (errno != ENOENT)
+               perror("sizeup open");
+       return 0;
   }
   if (ioctl(fd, DIOCGETP, &entry) == -1) {
-       perror("sizeup ioctl");
-       if(fstat(fd, &st) < 0) {
-               perror("fstat");
-               entry.size = cvu64(0);
-       } else {
-               fprintf(stderr, "used fstat instead\n");
-               entry.size = cvu64(st.st_size);
-       }
+       perror("sizeup ioctl");
+       if(fstat(fd, &st) < 0) {
+               perror("fstat");
+               entry.size = cvu64(0);
+       } else {
+               fprintf(stderr, "used fstat instead\n");
+               entry.size = cvu64(st.st_size);
+       }
   }
+
   close(fd);
   d = div64u(entry.size, block_size);
   rem = rem64u(entry.size, block_size);
@@ -439,6 +441,9 @@ ino_t inodes;
   for (cp = buf; cp < &buf[block_size]; cp++) *cp = 0;
   sup = (struct super_block *) buf;    /* lint - might use a union */
 
+  /* The assumption is that mkfs will create a clean FS. */
+  sup->s_flags = MFSFLAG_CLEAN;
+
   sup->s_ninodes = inodes;
   if (fs_version == 1) {
        sup->s_nzones = zones;
index 9e081fbd0952aa102ec2b6868f20f17439c8dbdc..dacf0ffa161e4466fc3b3703d1d4705dd78c0332 100644 (file)
@@ -3,7 +3,7 @@
 .include <bsd.own.mk>
 
 PROGRAMS= at_wini bios_wini cdprobe dev2name floppy loadramdisk mount \
-       pci procfs sh service sysenv mfs
+       pci procfs sh service sysenv mfs fsck.mfs
 SCRIPTS=newroot
 
 .if ${MKSMALL} != "yes"
@@ -43,6 +43,11 @@ bintoc:      bintoc.c
 
 image: proto.gen mtab rc $(EXTRA)
        mkfs.mfs image proto.gen || { rm -f image; false; }
+       if fsck.mfs -s image | grep -q CLEAN;   \
+       then    : ;     \
+       else    echo "CLEAN sanity check of image failed."      ;       \
+               echo "(Perhaps install current mkfs and fsck.)" ;       \
+       fi
 
 ahci: ../ahci/ahci
        install ${STRIPFLAG} ../$@/$@ $@
@@ -104,6 +109,12 @@ mount:  ../../commands/mount/mount
 ../../commands/mount/mount:
        $(MAKE) -C ../../commands/mount
 
+fsck.mfs:  ../../commands/fsck.mfs/fsck.mfs
+       install ${STRIPFLAG} ../../commands/$@/$@ $@
+
+../../commands/fsck.mfs/fsck.mfs:
+       $(MAKE) -C ../../commands/fsck.mfs
+
 newroot:  ../../commands/newroot/newroot.sh
        install ${STRIPFLAG} ../../commands/$@/$@.sh $@
 
index 54dd8643f405fb9cd8a429f6f775b806b8f59321..e3888188f94dec636e9c9693cc56f027d5216c74 100644 (file)
@@ -10,6 +10,7 @@ d--755 0 0
                sh ---755 0 0 sh
                service ---755 0 0 service
                sysenv ---755 0 0 sysenv
+               fsck.mfs ---755 0 0 fsck.mfs
        $
        sbin d--755 0 0
                @ACPI@
index 1ea5d8ad2045bbdd3fdd6bcbf944fbc88917b4cd..2bde8f43f8c8ae8c7bd01a091d34ee2664e9ee23 100644 (file)
@@ -5,6 +5,7 @@ exec >/dev/log
 exec 2>/dev/log
 exec </dev/null
 
+FSCK=/bin/fsck.mfs
 ACPI=/sbin/acpi
 if [ -e $ACPI -a -n "`sysenv acpi`" ]
 then
@@ -56,6 +57,10 @@ then
        loadramdisk "$ramimagename"
 fi
 echo "Root device name is $rootdevname"
+if [ -e $FSCK ]
+then   $FSCK -p $rootdevname
+fi
 /bin/newroot $bin_img"$rootdevname"
 /bin/mount -e -t procfs none /proc || echo "WARNING: couldn't mount procfs"
+
 exec /bin/sh /etc/rc "$@"
index df3e637b972998b9157a773ce770bec0d8dd1490..f5cb785df3b937097c4e6e1d7ee054a46882a45b 100644 (file)
@@ -38,7 +38,7 @@ install:: installpw   # installpw needed to bootstrap pw db
        install -m 644 -o root -g operator descr /usr/lib/
 
 
-installforce:: $(ETC)/rc $(ETC)/rs.inet $(ETC)/rs.single $(ETC)/system.conf $(USRETC)/rc $(USR)/Makefile installpw
+installforce:: $(ETC)/rc $(ETC)/rs.inet $(ETC)/rs.single $(ETC)/system.conf $(ETC)/rc.subr.minix $(USRETC)/rc $(USR)/Makefile installpw
 
 installpw::
        if [ ! -d $(ETC) ]; then mkdir $(ETC); chmod 755 $(ETC); fi
@@ -57,6 +57,9 @@ $(ETC)/rs.single: rs.single .PHONY
 $(ETC)/system.conf: system.conf .PHONY
        install -m 644 -o root -g operator $> $@
 
+$(ETC)/rc.subr.minix: rc.subr.minix .PHONY
+       install -m 644 -o root -g operator $> $@
+
 $(USRETC)/rc: usr/rc .PHONY
        install -m 755 -o root -g operator $> $@
 
index c98c86fd42aca3935a0a4398958b098a6f9e4914..963b51ad9d06635bc374f4f6fb66f4ceb7a23f39 100755 (executable)
@@ -2,7 +2,7 @@
 mountfstab()
 {
        fsck_opts=""
-       fflag=""
+       fflag="-p"
 
        while getopts "fo:" opt
        do      case $opt
@@ -18,13 +18,6 @@ mountfstab()
 
        shift `expr $OPTIND - 1`
 
-       # Make fsck necessary for unclean shutdown
-       msg="The system was not properly shut down.  Checking file systems."
-       if shutdown -C
-       then    echo "$msg"
-               fflag="-f"
-       fi
-
        fstabfile="$1"
 
        if [ ! -f $fstabfile ]
@@ -44,17 +37,16 @@ mountfstab()
                # This line's parameters
                dev="$1"; mp="$2"; fstype="$3"
 
+               # Don't fsck / as it's already mounted
+               if [ "$mp" = "/" ]; then continue; fi
+
                # Sanity checks
                if [ ! -b $dev ]; then  echo "$dev missing"; continue; fi
                if [ ! -d $mp ]; then echo "$mp missing"; continue; fi
 
                # Do fsck if necessary or requested
                if [ -n "$fflag" ]
-               then    echo "Checking $fstype $dev"
-                       if ! fsck.$fstype $fflag $fsck_opts -p $dev
-                       then    echo "$dev fail"
-                               continue
-                       fi
+               then    fsck.$fstype $fflag $fsck_opts $dev
                fi
 
                # Skip the actual mount for /, it's already mounted
index c583ab1e593762facd75103b85d46c656b827268..89b81b321774d8e143d2230c0919e7abd32dcc36 100644 (file)
@@ -11,7 +11,7 @@
  *   invalidate:  remove all the cache blocks on some device
  *
  * Private functions:
- *   rw_block:    read or write a block from the disk itself
+ *   read_block:    read or write a block from the disk itself
  */
 
 #include "fs.h"
 #include "inode.h"
 
 FORWARD _PROTOTYPE( void rm_lru, (struct buf *bp) );
-FORWARD _PROTOTYPE( void rw_block, (struct buf *, int) );
+FORWARD _PROTOTYPE( void read_block, (struct buf *) );
 
 PRIVATE int vmcache = 0; /* are we using vm's secondary cache? (initially not) */
 
+PRIVATE block_t super_start = 0, super_end = 0; 
+
 /*===========================================================================*
  *                             get_block                                    *
  *===========================================================================*/
@@ -183,7 +185,7 @@ PUBLIC struct buf *get_block(
        /* PREFETCH: don't do i/o. */
        bp->b_dev = NO_DEV;
   } else if (only_search == NORMAL) {
-       rw_block(bp, READING);
+       read_block(bp);
   } else if(only_search == NO_READ) {
        /* we want this block, but its contents
         * will be overwritten. VM has to forget
@@ -318,11 +320,10 @@ PUBLIC void free_zone(
 }
 
 /*===========================================================================*
- *                             rw_block                                     *
+ *                             read_block                                   *
  *===========================================================================*/
-PRIVATE void rw_block(bp, rw_flag)
+PRIVATE void read_block(bp)
 register struct buf *bp;       /* buffer pointer */
-int rw_flag;                   /* READING or WRITING */
 {
 /* Read or write a disk block. This is the only routine in which actual disk
  * I/O is invoked. If an error occurs, a message is printed here, but the error
@@ -337,12 +338,8 @@ int rw_flag;                       /* READING or WRITING */
 
   if ( (dev = bp->b_dev) != NO_DEV) {
        pos = mul64u(bp->b_blocknr, fs_block_size);
-       if (rw_flag == READING)
-               r = bdev_read(dev, pos, bp->b_data, fs_block_size,
-                       BDEV_NOFLAGS);
-       else
-               r = bdev_write(dev, pos, bp->b_data, fs_block_size,
-                       BDEV_NOFLAGS);
+       r = bdev_read(dev, pos, bp->b_data, fs_block_size,
+               BDEV_NOFLAGS);
        if (r < 0) {
                printf("MFS(%d) I/O error on device %d/%d, block %u\n",
                SELF_E, major(dev), minor(dev), bp->b_blocknr);
@@ -356,11 +353,9 @@ int rw_flag;                       /* READING or WRITING */
                bp->b_dev = NO_DEV;     /* invalidate block */
 
                /* Report read errors to interested parties. */
-               if (rw_flag == READING) rdwt_err = r;
+               rdwt_err = r;
        }
   }
-
-  MARKCLEAN(bp);
 }
 
 /*===========================================================================*
@@ -380,6 +375,27 @@ PUBLIC void invalidate(
   vm_forgetblocks();
 }
 
+/*===========================================================================*
+ *                             block_write_ok                               *
+ *===========================================================================*/
+int block_write_ok(struct buf *bp)
+{
+       if(superblock.s_dev != bp->b_dev) return 1;
+
+       if(bp->b_blocknr >= super_start && bp->b_blocknr <= super_end) {
+               printf("MFS: blocking write to superblock on mounted filesystem dev 0x%x.\n", bp->b_dev);
+               return 0;
+       }
+
+       if(superblock.s_rd_only) {
+               printf("MFS: blocking write to mounted readonly filesystem 0x%x.\n", bp->b_dev);
+               printf("This shouldn't happen.\n");
+               return 0;
+       }
+
+       return 1;
+}
+
 /*===========================================================================*
  *                             flushall                                     *
  *===========================================================================*/
@@ -404,8 +420,16 @@ PUBLIC void flushall(
        dirtylistsize = nr_bufs;
   }
 
-  for (bp = &buf[0], ndirty = 0; bp < &buf[nr_bufs]; bp++)
-       if (ISDIRTY(bp) && bp->b_dev == dev) dirty[ndirty++] = bp;
+  for (bp = &buf[0], ndirty = 0; bp < &buf[nr_bufs]; bp++) {
+       if (ISDIRTY(bp) && bp->b_dev == dev) {
+               if(!block_write_ok(bp)) {
+                       printf("MFS: LATE: ignoring changes in block %d\n", bp->b_blocknr);
+                       MARKCLEAN(bp);
+                       continue;
+               }
+               dirty[ndirty++] = bp;
+       }
+  }
   rw_scattered(dev, dirty, ndirty, WRITING);
 }
 
@@ -556,6 +580,8 @@ PRIVATE void cache_resize(unsigned int blocksize, unsigned int bufs)
   buf_pool(bufs);
 
   fs_block_size = blocksize;
+  super_start = SUPER_BLOCK_BYTES / fs_block_size;
+  super_end = (SUPER_BLOCK_BYTES + _MIN_BLOCK_SIZE - 1) / fs_block_size;
 }
 
 /*===========================================================================*
index c70d6a347c3f1f491f73ce5a0668deb52bd12d9c..bfb4d71720043f0e3f36a56dea1452de15b2fa38 100644 (file)
@@ -4,6 +4,7 @@
 #include <minix/vfsif.h>
 #include <minix/bdev.h>
 
+PRIVATE int cleanmount = 1;
 
 /*===========================================================================*
  *                             fs_readsuper                                 *
@@ -58,6 +59,25 @@ PUBLIC int fs_readsuper()
        return(r);
   }
 
+  /* Remember whether we were mounted cleanly so we know what to
+   * do at unmount time
+   */
+  if(superblock.s_flags & MFSFLAG_CLEAN)
+       cleanmount = 1;
+
+  /* clean check: if rw and not clean, switch to readonly */
+  if(!(superblock.s_flags & MFSFLAG_CLEAN) && !readonly) {
+       if(bdev_close(fs_dev) != OK)
+               panic("couldn't bdev_close after found unclean FS");
+       readonly = 1;
+
+       if (bdev_open(fs_dev, R_BIT) != OK) {
+               panic("couldn't bdev_open after found unclean FS");
+               return(EINVAL);
+       }
+       printf("MFS: WARNING: FS 0x%x unclean, mounting readonly\n", fs_dev);
+  }
+  
   set_blocksize(&superblock);
   
   /* Get the root inode of the mounted file system. */
@@ -88,6 +108,13 @@ PUBLIC int fs_readsuper()
 
   fs_m_out.RES_CONREQS = 1;    /* We can handle only 1 request at a time */
 
+  /* Mark it dirty */
+  if(!superblock.s_rd_only) {
+         superblock.s_flags &= ~MFSFLAG_CLEAN;
+         if(write_super(&superblock) != OK)
+               panic("mounting: couldn't write dirty superblock");
+  }
+
   return(r);
 }
 
@@ -151,6 +178,12 @@ PUBLIC int fs_unmount()
   /* force any cached blocks out of memory */
   (void) fs_sync();
 
+  /* Mark it clean if we're allowed to write _and_ it was clean originally. */
+  if(cleanmount && !superblock.s_rd_only) {
+       superblock.s_flags |= MFSFLAG_CLEAN;
+       write_super(&superblock);
+  }
+
   /* Close the device the file system lives on. */
   bdev_close(fs_dev);
 
index a2b754a67953f335056df6e539742fb5911b95d5..d88b557b73c6e598333a6746ef3d67b42b897472 100644 (file)
@@ -21,6 +21,7 @@ _PROTOTYPE( void put_block, (struct buf *bp, int block_type)          );
 _PROTOTYPE( void set_blocksize, (struct super_block *)                 );
 _PROTOTYPE( void rw_scattered, (dev_t dev,
                        struct buf **bufq, int bufqsize, int rw_flag)   );
+_PROTOTYPE( int block_write_ok, (struct buf *bp)                       );
 
 /* inode.c */
 _PROTOTYPE( struct inode *alloc_inode, (dev_t dev, mode_t bits)                );
@@ -93,6 +94,7 @@ _PROTOTYPE( void free_bit, (struct super_block *sp, int map,
 _PROTOTYPE( unsigned int get_block_size, (dev_t dev)                           );
 _PROTOTYPE( struct super_block *get_super, (dev_t dev)                 );
 _PROTOTYPE( int read_super, (struct super_block *sp)                   );
+_PROTOTYPE( int write_super, (struct super_block *sp)                  );
 
 /* stats.c */
 _PROTOTYPE( bit_t count_free_bits, (struct super_block *sp, int map));
index 6ec47b272800861ec704f4c9fbda07f676e6dfb1..d9cb4d360c00baad2b1d4338c6a521c77e8cd95c 100644 (file)
@@ -282,6 +282,10 @@ int *completed;                    /* number of bytes copied */
        /* Copy a chunk from the block buffer to user space. */
        r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) buf_off,
                           (vir_bytes) (bp->b_data+off), (size_t) chunk, D);
+  } else if(!block_write_ok(bp)) {
+       /* Let cache layer veto writing to this block */
+       printf("MFS: block write not allowed\n");
+       r = EPERM;
   } else {
        /* Copy a chunk from user space to the block buffer. */
        r = sys_safecopyfrom(VFS_PROC_NR, gid, (vir_bytes) buf_off,
index 3d7730dc331b385950df45219d8df57f80d8a443..a55133d337c25c98b7964c1c0d4336adcdab0383 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "fs.h"
 #include <string.h>
+#include <assert.h>
 #include <minix/com.h>
 #include <minix/u64.h>
 #include <minix/bdev.h>
@@ -157,7 +158,7 @@ PUBLIC struct super_block *get_super(
        panic("request for super_block of NO_DEV");
 
   if(superblock.s_dev != dev)
-       panic("wrong superblock: %d", (int) dev);
+       panic("wrong superblock: 0x%x", (int) dev);
 
   return(&superblock);
 }
@@ -177,31 +178,62 @@ PUBLIC unsigned int get_block_size(dev_t dev)
 
 
 /*===========================================================================*
- *                             read_super                                   *
+ *                             rw_super                                     *
  *===========================================================================*/
-PUBLIC int read_super(sp)
-register struct super_block *sp; /* pointer to a superblock */
+PRIVATE int rw_super(struct super_block *sp, int writing)
 {
-/* Read a superblock. */
-  dev_t dev;
-  unsigned int magic;
-  int version, native, r;
+/* Read/write a superblock. */
+  int r;
   static char *sbbuf;
-  block_t offset;
+  dev_t save_dev = sp->s_dev;
+
+/* To keep the 1kb on disk clean, only read/write up to and including
+ * this field.
+ */
+#define LAST_ONDISK_FIELD s_disk_version
+  int ondisk_bytes = (int) ((char *) &sp->LAST_ONDISK_FIELD - (char *) sp)
+       + sizeof(sp->LAST_ONDISK_FIELD);
 
   STATICINIT(sbbuf, _MIN_BLOCK_SIZE);
 
-  dev = sp->s_dev;             /* save device (will be overwritten by copy) */
-  if (dev == NO_DEV)
+  assert(ondisk_bytes > 0);
+  assert(ondisk_bytes < _MIN_BLOCK_SIZE);
+  assert(ondisk_bytes < sizeof(struct super_block));
+
+  if (sp->s_dev == NO_DEV)
        panic("request for super_block of NO_DEV");
-  
-  r = bdev_read(dev, cvu64(SUPER_BLOCK_BYTES), sbbuf, _MIN_BLOCK_SIZE,
-       BDEV_NOFLAGS);
+
+  if(writing) {
+       memset(sbbuf, 0, _MIN_BLOCK_SIZE);
+       memcpy(sbbuf, sp, ondisk_bytes);
+       r = bdev_write(sp->s_dev, cvu64(SUPER_BLOCK_BYTES), sbbuf, _MIN_BLOCK_SIZE,
+               BDEV_NOFLAGS);
+  } else {
+       r = bdev_read(sp->s_dev, cvu64(SUPER_BLOCK_BYTES), sbbuf, _MIN_BLOCK_SIZE,
+               BDEV_NOFLAGS);
+       memset(sp, 0, sizeof(*sp));
+       memcpy(sp, sbbuf, ondisk_bytes);
+       sp->s_dev = save_dev;
+  }
+
   if (r != _MIN_BLOCK_SIZE)
        return(EINVAL);
-  
-  memcpy(sp, sbbuf, sizeof(*sp));
-  sp->s_dev = NO_DEV;          /* restore later */
+
+  return OK;
+}
+
+/*===========================================================================*
+ *                             read_super                                   *
+ *===========================================================================*/
+PUBLIC int read_super(struct super_block *sp)
+{
+  unsigned int magic;
+  block_t offset;
+  int version, native, r;
+
+  if((r=rw_super(sp, 0)) != OK)
+       return r;
+
   magic = sp->s_magic;         /* determines file system type */
 
   /* Get file system version and type. */
@@ -306,7 +338,27 @@ register struct super_block *sp; /* pointer to a superblock */
                "or invalid first data zone, or zone size too large\n");
        return(EINVAL);
   }
-  sp->s_dev = dev;             /* restore device number */
+
+
+  /* Check any flags we don't understand but are required to. Currently
+   * these don't exist so all such unknown bits are fatal.
+   */
+  if(sp->s_flags & MFSFLAG_MANDATORY_MASK) {
+       printf("MFS: unsupported feature flags on this FS.\n"
+               "Please use a newer MFS to mount it.\n");
+       return(EINVAL);
+  }
+
   return(OK);
 }
 
+/*===========================================================================*
+ *                             write_super                                  *
+ *===========================================================================*/
+PUBLIC int write_super(struct super_block *sp)
+{
+  if(sp->s_rd_only)
+       panic("can't write superblock of readonly filesystem");
+  return rw_super(sp, 1);
+}
+
index 799fa481429a639d436a04030af6befba634935e..1b08d1d20cef248a5bdfc1af6afd88748255c611 100644 (file)
@@ -28,7 +28,7 @@ EXTERN struct super_block {
   short s_zmap_blocks;         /* # of blocks used by zone bit map */
   zone1_t s_firstdatazone_old; /* number of first data zone (small) */
   short s_log_zone_size;       /* log2 of blocks/zone */
-  short s_pad;                 /* try to avoid compiler-dependent padding */
+  unsigned short s_flags;      /* FS state flags */
   off_t s_max_size;            /* maximum file size on this device */
   zone_t s_zones;              /* number of zones (replaces s_nzones in V2) */
   short s_magic;               /* magic number to recognize super-blocks */
@@ -43,7 +43,11 @@ EXTERN struct super_block {
   unsigned short s_block_size; /* block size in bytes. */
   char s_disk_version;         /* filesystem format sub-version */
 
-  /* The following items are only used when the super_block is in memory. */
+  /* The following items are only used when the super_block is in memory.
+   * If this ever changes, i.e. more fields after s_disk_version has to go to
+   * disk, update LAST_ONDISK_FIELD in super.c as that controls which part of the
+   * struct is copied to and from disk.
+   */
   
   /*struct inode *s_isup;*/    /* inode for root dir of mounted file sys */
   /*struct inode *s_imount;*/   /* inode mounted on */
@@ -63,5 +67,17 @@ EXTERN struct super_block {
 #define IMAP           0       /* operating on the inode bit map */
 #define ZMAP           1       /* operating on the zone bit map */
 
+/* s_flags contents; undefined flags are guaranteed to be zero on disk
+ * (not counting future versions of mfs setting them!)
+ */
+#define MFSFLAG_CLEAN  (1L << 0) /* 0: dirty; 1: FS was unmounted cleanly */
+
+/* Future compatability (or at least, graceful failure):
+ * if any of these bits are on, and the MFS or fsck
+ * implementation doesn't understand them, do not mount/fsck
+ * the FS.
+ */
+#define MFSFLAG_MANDATORY_MASK 0xff00
+
 #endif