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:
parent
9a664b4984
commit
59ff5cbd87
13 changed files with 292 additions and 76 deletions
|
@ -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);
|
||||
|
|
|
@ -388,6 +388,7 @@ char *device;
|
|||
unsigned int rem;
|
||||
u64_t resize;
|
||||
|
||||
|
||||
if ((fd = open(device, O_RDONLY)) == -1) {
|
||||
if (errno != ENOENT)
|
||||
perror("sizeup open");
|
||||
|
@ -403,6 +404,7 @@ char *device;
|
|||
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;
|
||||
|
|
|
@ -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 $@
|
||||
|
||||
|
|
|
@ -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@
|
||||
|
|
|
@ -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 "$@"
|
||||
|
|
|
@ -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 $> $@
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
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;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue