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 <ben@minix3.org>
This commit is contained in:
Ben Gras 2011-12-22 01:29:27 +01:00
parent 9a664b4984
commit 59ff5cbd87
13 changed files with 292 additions and 76 deletions

View 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);

View 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;

View 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 $@

View 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@

View 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 "$@"

View 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 $> $@

View file

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

View 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"
@ -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;
}
/*===========================================================================*

View 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);

View 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));

View 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,

View 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);
}

View 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