From 59ff5cbd87291055162a1259caaa2baac67cd723 Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Thu, 22 Dec 2011 01:29:27 +0100 Subject: [PATCH] mfs: clean flag . 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 --- commands/fsck.mfs/fsck.c | 92 ++++++++++++++++++++++++++++++++++------ commands/mkfs.mfs/mkfs.c | 27 +++++++----- drivers/ramdisk/Makefile | 13 +++++- drivers/ramdisk/proto | 1 + drivers/ramdisk/rc | 5 +++ etc/Makefile | 5 ++- etc/rc.subr.minix | 18 +++----- servers/mfs/cache.c | 60 ++++++++++++++++++-------- servers/mfs/mount.c | 33 ++++++++++++++ servers/mfs/proto.h | 2 + servers/mfs/read.c | 4 ++ servers/mfs/super.c | 88 ++++++++++++++++++++++++++++++-------- servers/mfs/super.h | 20 ++++++++- 13 files changed, 292 insertions(+), 76 deletions(-) diff --git a/commands/fsck.mfs/fsck.c b/commands/fsck.mfs/fsck.c index 5f26a22bf..852a6fdea 100644 --- a/commands/fsck.mfs/fsck.c +++ b/commands/fsck.mfs/fsck.c @@ -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); diff --git a/commands/mkfs.mfs/mkfs.c b/commands/mkfs.mfs/mkfs.c index 8237c4bed..750aa2e24 100644 --- a/commands/mkfs.mfs/mkfs.c +++ b/commands/mkfs.mfs/mkfs.c @@ -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; diff --git a/drivers/ramdisk/Makefile b/drivers/ramdisk/Makefile index 9e081fbd0..dacf0ffa1 100644 --- a/drivers/ramdisk/Makefile +++ b/drivers/ramdisk/Makefile @@ -3,7 +3,7 @@ .include 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 $@ diff --git a/drivers/ramdisk/proto b/drivers/ramdisk/proto index 54dd8643f..e3888188f 100644 --- a/drivers/ramdisk/proto +++ b/drivers/ramdisk/proto @@ -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@ diff --git a/drivers/ramdisk/rc b/drivers/ramdisk/rc index 1ea5d8ad2..2bde8f43f 100644 --- a/drivers/ramdisk/rc +++ b/drivers/ramdisk/rc @@ -5,6 +5,7 @@ exec >/dev/log exec 2>/dev/log exec $@ +$(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 $> $@ diff --git a/etc/rc.subr.minix b/etc/rc.subr.minix index c98c86fd4..963b51ad9 100755 --- a/etc/rc.subr.minix +++ b/etc/rc.subr.minix @@ -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 diff --git a/servers/mfs/cache.c b/servers/mfs/cache.c index c583ab1e5..89b81b321 100644 --- a/servers/mfs/cache.c +++ b/servers/mfs/cache.c @@ -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" @@ -27,10 +27,12 @@ #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; } /*===========================================================================* diff --git a/servers/mfs/mount.c b/servers/mfs/mount.c index c70d6a347..bfb4d7172 100644 --- a/servers/mfs/mount.c +++ b/servers/mfs/mount.c @@ -4,6 +4,7 @@ #include #include +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); diff --git a/servers/mfs/proto.h b/servers/mfs/proto.h index a2b754a67..d88b557b7 100644 --- a/servers/mfs/proto.h +++ b/servers/mfs/proto.h @@ -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)); diff --git a/servers/mfs/read.c b/servers/mfs/read.c index 6ec47b272..d9cb4d360 100644 --- a/servers/mfs/read.c +++ b/servers/mfs/read.c @@ -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, diff --git a/servers/mfs/super.c b/servers/mfs/super.c index 3d7730dc3..a55133d33 100644 --- a/servers/mfs/super.c +++ b/servers/mfs/super.c @@ -13,6 +13,7 @@ #include "fs.h" #include +#include #include #include #include @@ -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); +} + diff --git a/servers/mfs/super.h b/servers/mfs/super.h index 799fa4814..1b08d1d20 100644 --- a/servers/mfs/super.h +++ b/servers/mfs/super.h @@ -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 -- 2.44.0