This patch changes the libminixfs API and implementation such that the library is at all times aware of how many total and used blocks there are in the file system. This removes the last upcall of libminixfs into file systems (fs_blockstats). In the process, make this part of the libminixfs API a little prettier and more robust. Change file systems accordingly. Since this change only adds to MFS being unable to deal with zones and blocks having different sizes, fail to mount such file systems immediately rather than triggering an assert later. Change-Id: I078e589c7e1be1fa691cf391bf5dfddd1baf2c86
174 lines
4.8 KiB
C
174 lines
4.8 KiB
C
#include "fs.h"
|
|
#include "inode.h"
|
|
#include "super.h"
|
|
#include <minix/vfsif.h>
|
|
#include <minix/bdev.h>
|
|
|
|
/*===========================================================================*
|
|
* fs_mount *
|
|
*===========================================================================*/
|
|
int fs_mount(dev_t dev, unsigned int flags, struct fsdriver_node *root_node,
|
|
unsigned int *res_flags)
|
|
{
|
|
/* This function reads the superblock of the partition, gets the root inode
|
|
* and sends back the details of them.
|
|
*/
|
|
struct inode *root_ip;
|
|
int r, readonly;
|
|
|
|
fs_dev = dev;
|
|
readonly = (flags & REQ_RDONLY) ? 1 : 0;
|
|
|
|
/* Open the device the file system lives on. */
|
|
if (bdev_open(fs_dev, readonly ? BDEV_R_BIT : (BDEV_R_BIT|BDEV_W_BIT) ) !=
|
|
OK) {
|
|
return(EINVAL);
|
|
}
|
|
|
|
/* Fill in the super block. */
|
|
superblock.s_dev = fs_dev; /* read_super() needs to know which dev */
|
|
r = read_super(&superblock);
|
|
|
|
/* Is it recognized as a Minix filesystem? */
|
|
if (r != OK) {
|
|
superblock.s_dev = NO_DEV;
|
|
bdev_close(fs_dev);
|
|
return(r);
|
|
}
|
|
|
|
/* 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, BDEV_R_BIT) != OK) {
|
|
panic("couldn't bdev_open after found unclean FS");
|
|
return(EINVAL);
|
|
}
|
|
printf("MFS: WARNING: FS 0x%llx unclean, mounting readonly\n", fs_dev);
|
|
}
|
|
|
|
lmfs_set_blocksize(superblock.s_block_size);
|
|
|
|
/* Compute the current number of used zones, and report it to libminixfs.
|
|
* Note that libminixfs really wants numbers of *blocks*, but this MFS
|
|
* implementation dropped support for differing zone/block sizes a while ago.
|
|
*/
|
|
used_zones = superblock.s_zones - count_free_bits(&superblock, ZMAP);
|
|
|
|
lmfs_set_blockusage(superblock.s_zones, used_zones);
|
|
|
|
/* Get the root inode of the mounted file system. */
|
|
if( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NULL) {
|
|
printf("MFS: couldn't get root inode\n");
|
|
superblock.s_dev = NO_DEV;
|
|
bdev_close(fs_dev);
|
|
return(EINVAL);
|
|
}
|
|
|
|
if(root_ip->i_mode == 0) {
|
|
printf("%s:%d zero mode for root inode?\n", __FILE__, __LINE__);
|
|
put_inode(root_ip);
|
|
superblock.s_dev = NO_DEV;
|
|
bdev_close(fs_dev);
|
|
return(EINVAL);
|
|
}
|
|
|
|
superblock.s_rd_only = readonly;
|
|
|
|
/* Root inode properties */
|
|
root_node->fn_ino_nr = root_ip->i_num;
|
|
root_node->fn_mode = root_ip->i_mode;
|
|
root_node->fn_size = root_ip->i_size;
|
|
root_node->fn_uid = root_ip->i_uid;
|
|
root_node->fn_gid = root_ip->i_gid;
|
|
root_node->fn_dev = NO_DEV;
|
|
|
|
*res_flags = RES_NOFLAGS;
|
|
|
|
/* 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);
|
|
}
|
|
|
|
|
|
/*===========================================================================*
|
|
* fs_mountpt *
|
|
*===========================================================================*/
|
|
int fs_mountpt(ino_t ino_nr)
|
|
{
|
|
/* This function looks up the mount point, it checks the condition whether
|
|
* the partition can be mounted on the inode or not.
|
|
*/
|
|
register struct inode *rip;
|
|
int r = OK;
|
|
mode_t bits;
|
|
|
|
/* Temporarily open the file. */
|
|
if( (rip = get_inode(fs_dev, ino_nr)) == NULL)
|
|
return(EINVAL);
|
|
|
|
if(rip->i_mountpoint) r = EBUSY;
|
|
|
|
/* It may not be special. */
|
|
bits = rip->i_mode & I_TYPE;
|
|
if (bits == I_BLOCK_SPECIAL || bits == I_CHAR_SPECIAL) r = ENOTDIR;
|
|
|
|
put_inode(rip);
|
|
|
|
if(r == OK) rip->i_mountpoint = TRUE;
|
|
|
|
return(r);
|
|
}
|
|
|
|
|
|
/*===========================================================================*
|
|
* fs_unmount *
|
|
*===========================================================================*/
|
|
void fs_unmount(void)
|
|
{
|
|
/* Unmount a file system. */
|
|
int count;
|
|
struct inode *rip, *root_ip;
|
|
|
|
/* See if the mounted device is busy. Only 1 inode using it should be
|
|
* open --the root inode-- and that inode only 1 time. This is an integrity
|
|
* check only: VFS expects the unmount to succeed either way.
|
|
*/
|
|
count = 0;
|
|
for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++)
|
|
if (rip->i_count > 0 && rip->i_dev == fs_dev) count += rip->i_count;
|
|
if (count != 1)
|
|
printf("MFS: file system has %d in-use inodes!\n", count);
|
|
|
|
if ((root_ip = find_inode(fs_dev, ROOT_INODE)) == NULL)
|
|
panic("MFS: couldn't find root inode\n");
|
|
|
|
put_inode(root_ip);
|
|
|
|
/* force any cached blocks out of memory */
|
|
fs_sync();
|
|
|
|
/* Mark it clean if we're allowed to write _and_ it was clean originally. */
|
|
if (!superblock.s_rd_only) {
|
|
superblock.s_flags |= MFSFLAG_CLEAN;
|
|
write_super(&superblock);
|
|
}
|
|
|
|
/* Close the device the file system lives on. */
|
|
bdev_close(fs_dev);
|
|
|
|
/* Throw out blocks out of the VM cache, to prevent corruption later. */
|
|
lmfs_invalidate(fs_dev);
|
|
|
|
/* Finish off the unmount. */
|
|
superblock.s_dev = NO_DEV;
|
|
}
|
|
|