VFS/FS: replace protocol version with flag field

The main motivation for this change is that only Loris supports
multithreading, and Loris supports dynamic thread allocation, so the
number of supported threads can be implemented as a bit flag (i.e.,
either 1 or "at least as many as VFS has"). The ABI break obviates the
need to support file system versioning at this time, and several
other aspects are better implemented as flags as well. Other changes:

- replace peek/bpeek test upon mount with FS flag as well;
- mark libsffs as 64-bit file size capable;
- remove old (3.2.1) getdents support.

Change-Id: I313eace9c50ed816656c31cd47d969033d952a03
This commit is contained in:
David van Moolenbroek 2013-08-31 21:48:15 +02:00 committed by Lionel Sambuc
parent ac65742ae4
commit cc810ee4d9
24 changed files with 47 additions and 847 deletions

View file

@ -39,8 +39,6 @@
#define REQ_TRC_START_LO m9_l3
#define REQ_UCRED_SIZE m9_s4
#define REQ_UID m9_s4
#define REQ_PROTO m9_s4 /* For definition see RES_PROTO */
/* VFS/FS reply fields */
#define RES_DEV m9_l4
@ -55,35 +53,12 @@
#define RES_SEEK_POS_LO m9_l4
#define RES_SYMLOOP m9_s3
#define RES_UID m9_s4
#define RES_PROTO m9_s3
/* RES_PROTO is defined as follows:
* |--------------------------------|
* 8O7 V 4 CR 0
* 15 0
* mentioned bits are inclusive
* CR: bits 4-0 encode no. concurrent requests are supported by FS
* V: bits 7-5 encode version of protocol
* O: bit 8 encodes support for 64-bit file offsets
*/
#define RES_PROTO_CR_SHIFT 0
#define RES_PROTO_CR_MASK 0x1F
#define VFS_FS_PROTO_CONREQS(b) (((b) & RES_PROTO_CR_MASK)>>RES_PROTO_CR_SHIFT)
#define VFS_FS_PROTO_PUT_CONREQS(b,v) \
((b) |= (((v) << RES_PROTO_CR_SHIFT) & RES_PROTO_CR_MASK))
#define RES_PROTO_V_SHIFT 5
#define RES_PROTO_V_MASK 0x70
#define VFS_FS_PROTO_VERSION(b) (((b) & RES_PROTO_V_MASK) >> RES_PROTO_V_SHIFT)
#define VFS_FS_PROTO_PUT_VERSION(b,v) \
((b) |= (((v) << RES_PROTO_V_SHIFT) & RES_PROTO_V_MASK))
#define VFS_FS_CURRENT_VERSION 1 /* Current version */
#define RES_PROTO_BIGOFFT_SHIFT 8
#define VFS_FS_PROTO_BIGOFFT(b) (b & RES_PROTO_BIGOFFT_SHIFT)
#define RES_FLAGS m9_s3
/* VFS/FS flags */
#define REQ_RDONLY 001
#define REQ_ISROOT 002
#define REQ_HASPROTO 004
#define REQ_RDONLY 001 /* FS is mounted read-only */
#define REQ_ISROOT 002 /* FS is root file system */
#define PATH_NOFLAGS 000
#define PATH_RET_SYMLINK 010 /* Return a symlink object (i.e.
* do not continue with the contents
@ -93,6 +68,11 @@
* and struct ucred size in m9_s4 (as
* opposed to a REQ_UID). */
#define RES_NOFLAGS 000
#define RES_THREADED 001 /* FS supports multithreading */
#define RES_HASPEEK 002 /* FS implements REQ_PEEK/REQ_BPEEK */
#define RES_64BIT 004 /* FS can handle 64-bit file sizes */
/* VFS/FS error messages */
#define EENTERMOUNT (-301)
#define ELEAVEMOUNT (-302)

View file

@ -33,9 +33,7 @@ int fs_readsuper()
fs_m_out.RES_FILE_SIZE_LO = root_va->va_size;
fs_m_out.RES_UID = root_va->va_uid;
fs_m_out.RES_GID = root_va->va_gid;
fs_m_out.RES_PROTO = 0;
VFS_FS_PROTO_PUT_VERSION(fs_m_out.RES_PROTO, VFS_FS_CURRENT_VERSION);
VFS_FS_PROTO_PUT_CONREQS(fs_m_out.RES_PROTO, 1);
fs_m_out.RES_FLAGS = RES_NOFLAGS;
return(OK);
}

View file

@ -62,9 +62,7 @@ int do_readsuper()
m_out.RES_UID = sffs_params->p_uid;
m_out.RES_GID = sffs_params->p_gid;
m_out.RES_DEV = NO_DEV;
m_out.RES_PROTO = 0;
VFS_FS_PROTO_PUT_VERSION(m_out.RES_PROTO, VFS_FS_CURRENT_VERSION);
VFS_FS_PROTO_PUT_CONREQS(m_out.RES_PROTO, 1);
m_out.RES_FLAGS = RES_64BIT;
state.s_mounted = TRUE;

View file

@ -8,7 +8,6 @@
EXTERN struct fs_hooks *vtreefs_hooks;
EXTERN int proto_version;
EXTERN message fs_m_in;
EXTERN message fs_m_out;

View file

@ -18,13 +18,6 @@ int fs_readsuper(void)
if (fs_m_in.REQ_FLAGS & REQ_ISROOT)
return EINVAL;
/* Get VFS-FS protocol version */
if (!(fs_m_in.REQ_FLAGS & REQ_HASPROTO)) {
proto_version = 0;
} else {
proto_version = VFS_FS_PROTO_VERSION(fs_m_in.REQ_PROTO);
}
/* Get the root inode and increase its reference count. */
root = get_root_inode();
ref_inode(root);
@ -41,10 +34,7 @@ int fs_readsuper(void)
fs_m_out.RES_UID = root->i_stat.uid;
fs_m_out.RES_GID = root->i_stat.gid;
fs_m_out.RES_DEV = NO_DEV;
fs_m_out.RES_PROTO = 0;
VFS_FS_PROTO_PUT_VERSION(fs_m_out.RES_PROTO, VFS_FS_CURRENT_VERSION);
VFS_FS_PROTO_PUT_CONREQS(fs_m_out.RES_PROTO, 1);
fs_m_out.RES_FLAGS = RES_NOFLAGS;
fs_mounted = TRUE;

View file

@ -67,153 +67,6 @@ int fs_read(void)
return r;
}
/*===========================================================================*
* fs_getdents_321 *
*===========================================================================*/
int fs_getdents_321(void)
{
/* Retrieve directory entries.
*/
struct inode *node, *child = NULL;
struct dirent_321 *dent;
char *name;
size_t len, off, user_off, user_left;
off_t pos;
int r, skip, get_next, indexed;
static char buf[GETDENTS_BUFSIZ];
if (fs_m_in.REQ_SEEK_POS_HI != 0)
return EIO;
if ((node = find_inode(fs_m_in.REQ_INODE_NR)) == NULL)
return EINVAL;
off = 0;
user_off = 0;
user_left = fs_m_in.REQ_MEM_SIZE;
indexed = node->i_indexed;
get_next = FALSE;
child = NULL;
/* Call the getdents hook, if any, to "refresh" the directory. */
if (!is_inode_deleted(node) && vtreefs_hooks->getdents_hook != NULL) {
r = vtreefs_hooks->getdents_hook(node, get_inode_cbdata(node));
if (r != OK) return r;
}
for (pos = fs_m_in.REQ_SEEK_POS_LO; ; pos++) {
/* Determine which inode and name to use for this entry. */
if (pos == 0) {
/* The "." entry. */
child = node;
name = ".";
}
else if (pos == 1) {
/* The ".." entry. */
child = get_parent_inode(node);
if (child == NULL)
child = node;
name = "..";
}
else if (pos - 2 < indexed) {
/* All indexed entries. */
child = get_inode_by_index(node, pos - 2);
/* If there is no inode with this particular index,
* continue with the next index number.
*/
if (child == NULL) continue;
name = child->i_name;
}
else {
/* All non-indexed entries. */
/* If this is the first loop iteration, first get to
* the non-indexed child identified by the current
* position.
*/
if (get_next == FALSE) {
skip = pos - indexed - 2;
child = get_first_inode(node);
/* Skip indexed children. */
while (child != NULL &&
child->i_index != NO_INDEX)
child = get_next_inode(child);
/* Skip to the right position. */
while (child != NULL && skip-- > 0)
child = get_next_inode(child);
get_next = TRUE;
}
else {
child = get_next_inode(child);
}
/* No more children? Then stop. */
if (child == NULL)
break;
assert(!is_inode_deleted(child));
name = child->i_name;
}
len = DWORD_ALIGN(sizeof(struct dirent_321) + strlen(name));
/* Is the user buffer too small to store another record? */
if (user_off + off + len > user_left) {
/* Is the user buffer too small for even a single
* record?
*/
if (user_off == 0 && off == 0)
return EINVAL;
break;
}
/* If our own buffer cannot contain the new record, copy out
* first.
*/
if (off + len > sizeof(buf)) {
r = sys_safecopyto(fs_m_in.m_source, fs_m_in.REQ_GRANT,
user_off, (vir_bytes) buf, off);
if (r != OK) return r;
user_off += off;
user_left -= off;
off = 0;
}
/* Fill in the actual directory entry. */
dent = (struct dirent_321 *) &buf[off];
dent->d_ino = (u32_t) get_inode_number(child);
dent->d_off = (i32_t) pos;
dent->d_reclen = len;
strcpy(dent->d_name, name);
off += len;
}
/* If there is anything left in our own buffer, copy that out now. */
if (off > 0) {
r = sys_safecopyto(fs_m_in.m_source, fs_m_in.REQ_GRANT,
user_off, (vir_bytes) buf, off);
if (r != OK)
return r;
user_off += off;
}
fs_m_out.RES_SEEK_POS_HI = 0;
fs_m_out.RES_SEEK_POS_LO = pos;
fs_m_out.RES_NBYTES = user_off;
return OK;
}
/*===========================================================================*
* fs_getdents *
*===========================================================================*/
@ -229,9 +82,6 @@ int fs_getdents(void)
int r, skip, get_next, indexed;
static char buf[GETDENTS_BUFSIZ];
if (proto_version == 0)
return fs_getdents_321();
if (fs_m_in.REQ_SEEK_POS_HI != 0)
return EIO;

View file

@ -21,8 +21,6 @@ extern char dot2[3]; /* meaning to search_dir: no access permission check. */
extern int(*fs_call_vec[]) (void);
EXTERN int proto_version;
EXTERN message fs_m_in;
EXTERN message fs_m_out;
EXTERN vfs_ucred_t credentials;

View file

@ -39,12 +39,6 @@ int fs_readsuper()
readonly = (fs_m_in.REQ_FLAGS & REQ_RDONLY) ? 1 : 0;
isroot = (fs_m_in.REQ_FLAGS & REQ_ISROOT) ? 1 : 0;
if (!(fs_m_in.REQ_FLAGS & REQ_HASPROTO)) {
proto_version = 0;
} else {
proto_version = VFS_FS_PROTO_VERSION(fs_m_in.REQ_PROTO);
}
if (label_len > sizeof(fs_dev_label))
return(EINVAL);
@ -163,9 +157,7 @@ int fs_readsuper()
fs_m_out.RES_FILE_SIZE_LO = root_ip->i_size;
fs_m_out.RES_UID = root_ip->i_uid;
fs_m_out.RES_GID = root_ip->i_gid;
fs_m_out.RES_PROTO = 0;
VFS_FS_PROTO_PUT_VERSION(fs_m_out.RES_PROTO, VFS_FS_CURRENT_VERSION);
VFS_FS_PROTO_PUT_CONREQS(fs_m_out.RES_PROTO, 1);
fs_m_out.RES_FLAGS = RES_HASPEEK;
return(r);
}

View file

@ -610,159 +610,6 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */
}
/*===========================================================================*
* fs_getdents_321 *
*===========================================================================*/
static int fs_getdents_321(void)
{
#define GETDENTS_321_BUFSIZE (sizeof(struct dirent_321) + EXT2_NAME_MAX + 1)
#define GETDENTS_321_ENTRIES 8
static char getdents_buf[GETDENTS_321_BUFSIZE * GETDENTS_321_ENTRIES];
struct inode *rip;
int o, r, done;
unsigned int block_size, len, reclen;
pino_t ino;
block_t b;
cp_grant_id_t gid;
size_t size, tmpbuf_off, userbuf_off;
off_t pos, off, block_pos, new_pos, ent_pos;
struct buf *bp;
struct ext2_disk_dir_desc *d_desc;
struct dirent *dep;
ino = (pino_t) fs_m_in.REQ_INODE_NR;
gid = (cp_grant_id_t) fs_m_in.REQ_GRANT;
size = (size_t) fs_m_in.REQ_MEM_SIZE;
pos = (off_t) fs_m_in.REQ_SEEK_POS_LO;
/* Check whether the position is properly aligned */
if ((unsigned int) pos % DIR_ENTRY_ALIGN)
return(ENOENT);
if ((rip = get_inode(fs_dev, ino)) == NULL)
return(EINVAL);
block_size = rip->i_sp->s_block_size;
off = (pos % block_size); /* Offset in block */
block_pos = pos - off;
done = FALSE; /* Stop processing directory blocks when done is set */
memset(getdents_buf, '\0', sizeof(getdents_buf)); /* Avoid leaking any data */
tmpbuf_off = 0; /* Offset in getdents_buf */
userbuf_off = 0; /* Offset in the user's buffer */
/* The default position for the next request is EOF. If the user's buffer
* fills up before EOF, new_pos will be modified. */
new_pos = rip->i_size;
for (; block_pos < rip->i_size; block_pos += block_size) {
off_t temp_pos = block_pos;
b = read_map(rip, block_pos, 0); /* get block number */
/* Since directories don't have holes, 'b' cannot be NO_BLOCK. */
bp = get_block(rip->i_dev, b, NORMAL); /* get a dir block */
assert(bp != NULL);
/* Search a directory block. */
d_desc = (struct ext2_disk_dir_desc*) &b_data(bp);
/* we need to seek to entry at off bytes.
* when NEXT_DISC_DIR_POS == block_size it's last dentry.
*/
for (; temp_pos + conv2(le_CPU, d_desc->d_rec_len) <= pos
&& NEXT_DISC_DIR_POS(d_desc, &b_data(bp)) < block_size;
d_desc = NEXT_DISC_DIR_DESC(d_desc)) {
temp_pos += conv2(le_CPU, d_desc->d_rec_len);
}
for (; CUR_DISC_DIR_POS(d_desc, &b_data(bp)) < block_size;
d_desc = NEXT_DISC_DIR_DESC(d_desc)) {
if (d_desc->d_ino == 0)
continue; /* Entry is not in use */
#if 0 /* d_nam_len is a uint8_t, so the test is always false. */
if (d_desc->d_name_len > NAME_MAX ||
d_desc->d_name_len > EXT2_NAME_MAX) {
len = min(NAME_MAX, EXT2_NAME_MAX);
} else {
len = d_desc->d_name_len;
}
#endif
len = d_desc->d_name_len;
/* Compute record length */
reclen = offsetof(struct dirent_321, d_name) + len + 1;
o = (reclen % sizeof(long));
if (o != 0)
reclen += sizeof(long) - o;
/* Need the position of this entry in the directory */
ent_pos = block_pos + ((char *)d_desc - b_data(bp));
if (userbuf_off + tmpbuf_off + reclen >= size) {
/* The user has no space for one more record */
done = TRUE;
/* Record the position of this entry, it is the
* starting point of the next request (unless the
* position is modified with lseek).
*/
new_pos = ent_pos;
break;
}
if (tmpbuf_off + reclen >=
GETDENTS_321_BUFSIZE * GETDENTS_321_ENTRIES) {
r = sys_safecopyto(VFS_PROC_NR, gid,
(vir_bytes) userbuf_off,
(vir_bytes) getdents_buf,
(size_t) tmpbuf_off);
if (r != OK) {
put_inode(rip);
return(r);
}
userbuf_off += tmpbuf_off;
tmpbuf_off = 0;
}
dep = (struct dirent *) &getdents_buf[tmpbuf_off];
dep->d_ino = (u32_t) conv4(le_CPU, d_desc->d_ino);
dep->d_off = (i32_t) ent_pos;
dep->d_reclen = (unsigned short) reclen;
memcpy(dep->d_name, d_desc->d_name, len);
dep->d_name[len] = '\0';
tmpbuf_off += reclen;
}
put_block(bp, DIRECTORY_BLOCK);
if (done)
break;
}
if (tmpbuf_off != 0) {
r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) userbuf_off,
(vir_bytes) getdents_buf, (size_t) tmpbuf_off);
if (r != OK) {
put_inode(rip);
return(r);
}
userbuf_off += tmpbuf_off;
}
if (done && userbuf_off == 0)
r = EINVAL; /* The user's buffer is too small */
else {
fs_m_out.RES_NBYTES = userbuf_off;
fs_m_out.RES_SEEK_POS_LO = new_pos;
rip->i_update |= ATIME;
rip->i_dirt = IN_DIRTY;
r = OK;
}
put_inode(rip); /* release the inode */
return(r);
}
/*===========================================================================*
* fs_getdents *
*===========================================================================*/
@ -782,10 +629,6 @@ int fs_getdents(void)
struct ext2_disk_dir_desc *d_desc;
struct dirent *dep;
if (proto_version == 0) {
return fs_getdents_321();
}
ino = (pino_t) fs_m_in.REQ_INODE_NR;
gid = (cp_grant_id_t) fs_m_in.REQ_GRANT;
size = (size_t) fs_m_in.REQ_MEM_SIZE;

View file

@ -19,7 +19,6 @@ EXTERN int FS_STATE;
EXTERN uid_t caller_uid;
EXTERN gid_t caller_gid;
EXTERN int proto_version;
EXTERN int req_nr; /* request number to the server */
EXTERN int SELF_E; /* process number */

View file

@ -18,12 +18,6 @@ int fs_readsuper() {
label_gid = fs_m_in.REQ_GRANT;
label_len = fs_m_in.REQ_PATH_LEN;
if (!(fs_m_in.REQ_FLAGS & REQ_HASPROTO)) {
proto_version = 0;
} else {
proto_version = VFS_FS_PROTO_VERSION(fs_m_in.REQ_PROTO);
}
if (label_len > sizeof(fs_dev_label))
return(EINVAL);
@ -57,9 +51,7 @@ int fs_readsuper() {
fs_m_out.RES_FILE_SIZE_LO = v_pri.dir_rec_root->d_file_size;
fs_m_out.RES_UID = SYS_UID; /* Always root */
fs_m_out.RES_GID = SYS_GID; /* operator */
fs_m_out.RES_PROTO = 0;
VFS_FS_PROTO_PUT_VERSION(fs_m_out.RES_PROTO, VFS_FS_CURRENT_VERSION);
VFS_FS_PROTO_PUT_CONREQS(fs_m_out.RES_PROTO, 1);
fs_m_out.RES_FLAGS = RES_NOFLAGS;
return(r);
}

View file

@ -136,153 +136,6 @@ int fs_bread(void)
}
/*===========================================================================*
* fs_getdents_321 *
*===========================================================================*/
int fs_getdents_321(void) {
struct dir_record *dir;
pino_t ino;
cp_grant_id_t gid;
size_t block_size;
off_t pos, block_pos, block, cur_pos, tmpbuf_offset, userbuf_off;
struct buf *bp;
struct dir_record *dir_tmp;
struct dirent *dirp;
int r,done,o,len,reclen;
char *cp;
char name[NAME_MAX + 1];
char name_old[NAME_MAX + 1];
/* Initialize the tmp arrays */
memset(name,'\0',NAME_MAX);
memset(name_old,'\0',NAME_MAX);
/* Get input parameters */
ino = fs_m_in.REQ_INODE_NR;
gid = fs_m_in.REQ_GRANT;
pos = fs_m_in.REQ_SEEK_POS_LO;
block_size = v_pri.logical_block_size_l;
cur_pos = pos; /* The current position */
tmpbuf_offset = 0;
userbuf_off = 0;
memset(getdents_buf, '\0', GETDENTS_BUFSIZ); /* Avoid leaking any data */
if ((dir = get_dir_record(ino)) == NULL) return(EINVAL);
block = dir->loc_extent_l; /* First block of the directory */
block += pos / block_size; /* Shift to the block where start to read */
done = FALSE;
while (cur_pos<dir->d_file_size) {
bp = get_block(block); /* Get physical block */
if (bp == NULL) {
release_dir_record(dir);
return(EINVAL);
}
block_pos = cur_pos % block_size; /* Position where to start read */
while (block_pos < block_size) {
dir_tmp = get_free_dir_record();
create_dir_record(dir_tmp,b_data(bp) + block_pos,
block*block_size + block_pos);
if (dir_tmp->length == 0) { /* EOF. I exit and return 0s */
block_pos = block_size;
done = TRUE;
release_dir_record(dir_tmp);
} else { /* The dir record is valid. Copy data... */
if (dir_tmp->file_id[0] == 0)
strlcpy(name, ".", NAME_MAX + 1);
else if (dir_tmp->file_id[0] == 1)
strlcpy(name, "..", NAME_MAX + 1);
else {
/* Extract the name from the field file_id */
strncpy(name, dir_tmp->file_id,
dir_tmp->length_file_id);
name[dir_tmp->length_file_id] = 0;
/* Tidy up file name */
cp = memchr(name, ';', NAME_MAX);
if (cp != NULL) name[cp - name] = 0;
/*If no file extension, then remove final '.'*/
if (name[strlen(name) - 1] == '.')
name[strlen(name) - 1] = '\0';
}
if (strcmp(name_old, name) == 0) {
cur_pos += dir_tmp->length;
release_dir_record(dir_tmp);
continue;
}
strlcpy(name_old, name, NAME_MAX + 1);
/* Compute the length of the name */
cp = memchr(name, '\0', NAME_MAX);
if (cp == NULL) len = NAME_MAX;
else len= cp - name;
/* Compute record length */
reclen = offsetof(struct dirent, d_name) + len + 1;
o = (reclen % sizeof(long));
if (o != 0)
reclen += sizeof(long) - o;
/* If the new record does not fit, then copy the buffer
* and start from the beginning. */
if (tmpbuf_offset + reclen > GETDENTS_BUFSIZ) {
r = sys_safecopyto(VFS_PROC_NR, gid, userbuf_off,
(vir_bytes)getdents_buf, tmpbuf_offset);
if (r != OK)
panic("fs_getdents: sys_safecopyto failed: %d", r);
userbuf_off += tmpbuf_offset;
tmpbuf_offset= 0;
}
/* The standard data structure is created using the
* data in the buffer. */
dirp = (struct dirent *) &getdents_buf[tmpbuf_offset];
dirp->d_ino = (u32_t) (b_data(bp) + block_pos);
dirp->d_off= (i32_t) cur_pos;
dirp->d_reclen= reclen;
memcpy(dirp->d_name, name, len);
dirp->d_name[len]= '\0';
tmpbuf_offset += reclen;
cur_pos += dir_tmp->length;
release_dir_record(dir_tmp);
}
block_pos += dir_tmp->length;
}
put_block(bp); /* release the block */
if (done == TRUE) break;
cur_pos += block_size - cur_pos;
block++; /* read the next one */
}
if (tmpbuf_offset != 0) {
r = sys_safecopyto(VFS_PROC_NR, gid, userbuf_off,
(vir_bytes) getdents_buf, tmpbuf_offset);
if (r != OK)
panic("fs_getdents: sys_safecopyto failed: %d", r);
userbuf_off += tmpbuf_offset;
}
fs_m_out.RES_NBYTES = userbuf_off;
fs_m_out.RES_SEEK_POS_LO = cur_pos;
release_dir_record(dir); /* release the inode */
return(OK);
}
/*===========================================================================*
* fs_getdents *
*===========================================================================*/
@ -300,10 +153,6 @@ int fs_getdents(void) {
char name[NAME_MAX + 1];
char name_old[NAME_MAX + 1];
if (proto_version == 0) {
return fs_getdents_321();
}
/* Initialize the tmp arrays */
memset(name,'\0',NAME_MAX);
memset(name_old,'\0',NAME_MAX);

View file

@ -27,7 +27,6 @@ EXTERN uid_t caller_uid;
EXTERN gid_t caller_gid;
EXTERN int req_nr;
EXTERN int proto_version;
EXTERN endpoint_t SELF_E;

View file

@ -30,12 +30,6 @@ int fs_readsuper()
readonly = (fs_m_in.REQ_FLAGS & REQ_RDONLY) ? 1 : 0;
isroot = (fs_m_in.REQ_FLAGS & REQ_ISROOT) ? 1 : 0;
if (!(fs_m_in.REQ_FLAGS & REQ_HASPROTO)) {
proto_version = 0;
} else {
proto_version = VFS_FS_PROTO_VERSION(fs_m_in.REQ_PROTO);
}
if (label_len > sizeof(fs_dev_label))
return(EINVAL);
@ -111,9 +105,7 @@ int fs_readsuper()
fs_m_out.RES_FILE_SIZE_LO = root_ip->i_size;
fs_m_out.RES_UID = root_ip->i_uid;
fs_m_out.RES_GID = root_ip->i_gid;
fs_m_out.RES_PROTO = 0;
VFS_FS_PROTO_PUT_VERSION(fs_m_out.RES_PROTO, VFS_FS_CURRENT_VERSION);
VFS_FS_PROTO_PUT_CONREQS(fs_m_out.RES_PROTO, 1);
fs_m_out.RES_FLAGS = RES_HASPEEK;
/* Mark it dirty */
if(!superblock.s_rd_only) {

View file

@ -67,7 +67,6 @@ int search_dir(struct inode *ldir_ptr, char string [MFS_NAME_MAX], pino_t
int fs_chmod(void);
int fs_chown(void);
int fs_getdents(void);
int fs_getdents_321(void);
int forbidden(struct inode *rip, pmode_t access_desired);
int read_only(struct inode *ip);

View file

@ -604,153 +604,6 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */
}
/*===========================================================================*
* fs_getdents_321 *
*===========================================================================*/
int fs_getdents_321(void)
{
#define GETDENTS_321_BUFSIZE (sizeof(struct dirent_321) + MFS_NAME_MAX + 1)
#define GETDENTS_321_ENTRIES 8
static char getdents_buf[GETDENTS_321_BUFSIZE * GETDENTS_321_ENTRIES];
register struct inode *rip;
int o, r, done;
unsigned int block_size, len, reclen;
pino_t ino;
block_t b;
cp_grant_id_t gid;
size_t size, tmpbuf_off, userbuf_off;
off_t pos, off, block_pos, new_pos, ent_pos;
struct buf *bp;
struct direct *dp;
struct dirent_321 *dep;
char *cp;
ino = (pino_t) fs_m_in.REQ_INODE_NR;
gid = (cp_grant_id_t) fs_m_in.REQ_GRANT;
size = (size_t) fs_m_in.REQ_MEM_SIZE;
pos = (off_t) fs_m_in.REQ_SEEK_POS_LO;
/* Check whether the position is properly aligned */
if ((unsigned int) pos % DIR_ENTRY_SIZE)
return(ENOENT);
if ((rip = get_inode(fs_dev, ino)) == NULL)
return(EINVAL);
block_size = rip->i_sp->s_block_size;
off = (pos % block_size); /* Offset in block */
block_pos = pos - off;
done = FALSE; /* Stop processing directory blocks when done is set */
tmpbuf_off = 0; /* Offset in getdents_buf */
memset(getdents_buf, '\0', sizeof(getdents_buf)); /* Avoid leaking any data */
userbuf_off = 0; /* Offset in the user's buffer */
/* The default position for the next request is EOF. If the user's buffer
* fills up before EOF, new_pos will be modified. */
new_pos = rip->i_size;
for(; block_pos < rip->i_size; block_pos += block_size) {
b = read_map(rip, block_pos, 0); /* get block number */
/* Since directories don't have holes, 'b' cannot be NO_BLOCK. */
bp = get_block(rip->i_dev, b, NORMAL); /* get a dir block */
assert(bp != NULL);
/* Search a directory block. */
if (block_pos < pos)
dp = &b_dir(bp)[off / DIR_ENTRY_SIZE];
else
dp = &b_dir(bp)[0];
for (; dp < &b_dir(bp)[NR_DIR_ENTRIES(block_size)]; dp++) {
if (dp->mfs_d_ino == 0)
continue; /* Entry is not in use */
/* Compute the length of the name */
cp = memchr(dp->mfs_d_name, '\0', sizeof(dp->mfs_d_name));
if (cp == NULL)
len = sizeof(dp->mfs_d_name);
else
len = cp - (dp->mfs_d_name);
/* Compute record length */
reclen = offsetof(struct dirent_321, d_name) + len + 1;
o = (reclen % sizeof(long));
if (o != 0)
reclen += sizeof(long) - o;
/* Need the position of this entry in the directory */
ent_pos = block_pos + ((char *) dp - (char *) bp->data);
if (userbuf_off + tmpbuf_off + reclen >= size) {
/* The user has no space for one more record */
done = TRUE;
/* Record the position of this entry, it is the
* starting point of the next request (unless the
* postion is modified with lseek).
*/
new_pos = ent_pos;
break;
}
if (tmpbuf_off + reclen >=
GETDENTS_321_BUFSIZE * GETDENTS_321_ENTRIES) {
r = sys_safecopyto(VFS_PROC_NR, gid,
(vir_bytes) userbuf_off,
(vir_bytes) getdents_buf,
(size_t) tmpbuf_off);
if (r != OK) {
put_inode(rip);
return(r);
}
userbuf_off += tmpbuf_off;
tmpbuf_off = 0;
}
dep = (struct dirent_321 *) &getdents_buf[tmpbuf_off];
dep->d_ino = (u32_t) dp->mfs_d_ino;
dep->d_off = (i32_t) ent_pos;
dep->d_reclen = (unsigned short) reclen;
memcpy(dep->d_name, dp->mfs_d_name, len);
dep->d_name[len] = '\0';
tmpbuf_off += reclen;
}
put_block(bp, DIRECTORY_BLOCK);
if (done)
break;
}
if (tmpbuf_off != 0) {
r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) userbuf_off,
(vir_bytes) getdents_buf, (size_t) tmpbuf_off);
if (r != OK) {
put_inode(rip);
return(r);
}
userbuf_off += tmpbuf_off;
}
if (done && userbuf_off == 0)
r = EINVAL; /* The user's buffer is too small */
else {
fs_m_out.RES_NBYTES = userbuf_off;
fs_m_out.RES_SEEK_POS_LO = new_pos;
if(!rip->i_sp->s_rd_only) {
rip->i_update |= ATIME;
IN_MARKDIRTY(rip);
}
r = OK;
}
put_inode(rip); /* release the inode */
return(r);
}
/*===========================================================================*
* fs_getdents *
*===========================================================================*/
@ -771,12 +624,6 @@ int fs_getdents(void)
struct dirent *dep;
char *cp;
if (proto_version == 0) {
/* VFS-FS protocol version 0 uses 32-bits ino_t and off_t. We need to
* use the binary compatible version of this routine */
return fs_getdents_321();
}
ino = (pino_t) fs_m_in.REQ_INODE_NR;
gid = (cp_grant_id_t) fs_m_in.REQ_GRANT;
size = (size_t) fs_m_in.REQ_MEM_SIZE;

View file

@ -343,7 +343,8 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
{
struct vnode *vp = execi.vp;
assert(vp);
if(vp->v_vmnt->m_haspeek && major(vp->v_dev) != MEMORY_MAJOR) {
if ((vp->v_vmnt->m_fs_flags & RES_HASPEEK) &&
major(vp->v_dev) != MEMORY_MAJOR) {
int newfd = -1;
if(get_fd(vmfp, 0, R_BIT, &newfd, &newfilp) == OK) {
assert(newfd >= 0 && newfd < OPEN_MAX);

View file

@ -331,7 +331,7 @@ int dupvm(struct fproc *rfp, int pfd, int *vmfd, struct filp **newfilp)
return EBADF;
}
if(!f->filp_vno->v_vmnt->m_haspeek) {
if(!(f->filp_vno->v_vmnt->m_fs_flags & RES_HASPEEK)) {
unlock_filp(f);
#if 0 /* Noisy diagnostic for mmap() by ld.so */
printf("VFS dupvm: no peek available\n");

View file

@ -184,6 +184,7 @@ char mount_label[LABEL_MAX] )
struct node_details res;
struct lookup resolve;
struct statvfs statvfs_buf;
unsigned int fs_flags;
/* Look up block device driver label when dev is not a pseudo-device */
label = "";
@ -281,15 +282,11 @@ char mount_label[LABEL_MAX] )
/* Tell FS which device to mount */
new_vmp->m_flags |= VMNT_MOUNTING;
r = req_readsuper(new_vmp, label, dev, !!(flags & MNT_RDONLY), isroot, &res);
r = req_readsuper(new_vmp, label, dev, !!(flags & MNT_RDONLY), isroot, &res,
&fs_flags);
new_vmp->m_flags &= ~VMNT_MOUNTING;
if(req_peek(fs_e, 1, 0, PAGE_SIZE) != OK ||
req_bpeek(fs_e, dev, 0, PAGE_SIZE) != OK) {
new_vmp->m_haspeek = 0;
} else {
new_vmp->m_haspeek = 1;
}
new_vmp->m_fs_flags = fs_flags;
/* Fill the statvfs cache with initial values. */
if (r == OK)
@ -322,10 +319,10 @@ char mount_label[LABEL_MAX] )
/* Root node is indeed on the partition */
root_node->v_vmnt = new_vmp;
root_node->v_dev = new_vmp->m_dev;
if (VFS_FS_PROTO_CONREQS(new_vmp->m_proto) == 0)
new_vmp->m_comm.c_max_reqs = 1; /* Default if FS doesn't tell us */
if (!(new_vmp->m_fs_flags & RES_THREADED))
new_vmp->m_comm.c_max_reqs = 1;
else
new_vmp->m_comm.c_max_reqs = VFS_FS_PROTO_CONREQS(new_vmp->m_proto);
new_vmp->m_comm.c_max_reqs = NR_WTHREADS;
new_vmp->m_comm.c_cur_reqs = 0;
/* No more blocking operations, so we can now report on this file system. */
@ -422,9 +419,7 @@ void mount_pfs(void)
vmp->m_dev = dev;
vmp->m_fs_e = PFS_PROC_NR;
vmp->m_proto = 0;
VFS_FS_PROTO_PUT_CONREQS(vmp->m_proto, 1);
VFS_FS_PROTO_PUT_VERSION(vmp->m_proto, VFS_FS_CURRENT_VERSION);
vmp->m_fs_flags = 0;
strlcpy(vmp->m_label, "pfs", LABEL_MAX);
strlcpy(vmp->m_mount_path, "pipe", PATH_MAX);
strlcpy(vmp->m_mount_dev, "none", PATH_MAX);

View file

@ -626,7 +626,7 @@ char ename[NAME_MAX + 1];
do {
r = req_getdents(dirp->v_fs_e, dirp->v_inode_nr, pos, buf, sizeof(buf),
&new_pos, 1, 0 /* Not MINIX 3.2.1 format */);
&new_pos, 1);
if (r == 0) {
return(ENOENT); /* end of entries -- matching inode !found */

View file

@ -242,7 +242,7 @@ int req_flush(endpoint_t fs_e, dev_t dev);
int req_statvfs(endpoint_t fs_e, struct statvfs *buf);
int req_ftrunc(endpoint_t fs_e, ino_t inode_nr, off_t start, off_t end);
int req_getdents(endpoint_t fs_e, ino_t inode_nr, off_t pos, char *buf,
size_t size, off_t *new_pos, int direct, int getdents_321);
size_t size, off_t *new_pos, int direct);
int req_inhibread(endpoint_t fs_e, ino_t inode_nr);
int req_link(endpoint_t fs_e, ino_t link_parent, char *lastc,
ino_t linked_file);
@ -260,7 +260,7 @@ int req_putnode(int fs_e, ino_t inode_nr, int count);
int req_rdlink(endpoint_t fs_e, ino_t inode_nr, endpoint_t proc_e,
vir_bytes buf, size_t len, int direct);
int req_readsuper(struct vmnt *vmp, char *driver_name, dev_t dev, int readonly,
int isroot, struct node_details *res_nodep);
int isroot, struct node_details *res_nodep, unsigned int *fs_flags);
int req_readwrite(endpoint_t fs_e, ino_t inode_nr, off_t pos, int rw_flag,
endpoint_t user_e, vir_bytes user_addr, unsigned int num_of_bytes,
off_t *new_posp, unsigned int *cum_iop);

View file

@ -257,11 +257,10 @@ int read_write(struct fproc *rfp, int rw_flag, struct filp *f,
int do_getdents(message *UNUSED(m_out))
{
/* Perform the getdents(fd, buf, size) system call. */
int r = OK, getdents_321 = 0;
int r = OK;
off_t new_pos;
register struct filp *rfilp;
if (job_call_nr == GETDENTS_321) getdents_321 = 1;
scratch(fp).file.fd_nr = job_m_in.fd;
scratch(fp).io.io_buffer = job_m_in.buffer;
scratch(fp).io.io_nbytes = (size_t) job_m_in.nbytes;
@ -278,7 +277,7 @@ int do_getdents(message *UNUSED(m_out))
if (r == OK) {
r = req_getdents(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr,
rfilp->filp_pos, scratch(fp).io.io_buffer,
scratch(fp).io.io_nbytes, &new_pos, 0, getdents_321);
scratch(fp).io.io_nbytes, &new_pos, 0);
if (r > 0) rfilp->filp_pos = new_pos;
}

View file

@ -26,8 +26,6 @@
#include "vnode.h"
static size_t translate_dents(char *src, size_t size, char *dst, int direction);
/*===========================================================================*
* req_breadwrite *
*===========================================================================*/
@ -194,7 +192,7 @@ int req_create(
res->fs_e = m.m_source;
res->inode_nr = (ino_t) m.RES_INODE_NR;
res->fmode = (mode_t) m.RES_MODE;
if (VFS_FS_PROTO_BIGOFFT(vmp->m_proto)) {
if (vmp->m_fs_flags & RES_64BIT) {
res->fsize = make64(m.RES_FILE_SIZE_LO, m.RES_FILE_SIZE_HI);
} else {
res->fsize = m.RES_FILE_SIZE_LO;
@ -264,7 +262,7 @@ int req_ftrunc(endpoint_t fs_e, ino_t inode_nr, off_t start, off_t end)
m.REQ_INODE_NR = (pino_t) inode_nr;
m.REQ_TRC_START_LO = ex64lo(start);
if (VFS_FS_PROTO_BIGOFFT(vmp->m_proto)) {
if (vmp->m_fs_flags & RES_64BIT) {
m.REQ_TRC_START_HI = ex64hi(start);
} else if (start > INT_MAX) {
/* FS does not support 64-bit off_t and 32 bits is not enough */
@ -274,7 +272,7 @@ int req_ftrunc(endpoint_t fs_e, ino_t inode_nr, off_t start, off_t end)
}
m.REQ_TRC_END_LO = ex64lo(end);
if (VFS_FS_PROTO_BIGOFFT(vmp->m_proto)) {
if (vmp->m_fs_flags & RES_64BIT) {
m.REQ_TRC_END_HI = ex64hi(end);
} else if (end > INT_MAX) {
/* FS does not support 64-bit off_t and 32 bits is not enough */
@ -298,61 +296,18 @@ int req_getdents(
char *buf,
size_t size,
off_t *new_pos,
int direct,
int getdents_321 /* Set to 1 if user land expects old format */
int direct
)
{
int r;
int fs_getdents_321 = 0, do_translation = 0;
message m;
cp_grant_id_t grant_id;
struct vmnt *vmp;
char *indir_buf_src = NULL;
char *indir_buf_dst = NULL;
vmp = find_vmnt(fs_e);
assert(vmp != NULL);
if (VFS_FS_PROTO_VERSION(vmp->m_proto) == 0) {
fs_getdents_321 = 1;
}
/* When we have to translate new struct dirent to the old format or vice
* versa, we're going to have to ignore the user provided buffer and do only
* one entry at a time. We have to do the translation here and allocate
* space on the stack. This is a limited resource. Besides, we don't want to
* be dependent on crazy buffer sizes provided by user space (i.e., we'd have
* to allocate a similarly sized buffer here).
*
* We need to translate iff:
* 1. userland expects old format and FS provides new format
* 2. userland expects new format and FS provides old format
* We don't need to translate iff
* 3. userland expects old format and FS provides old format
* 4. userland expects new format and FS provides new format
*
* Note: VFS expects new format (when doing 'direct'), covered by case 2.
*/
if (getdents_321 && !fs_getdents_321) { /* case 1 */
do_translation = 1;
} else if (fs_getdents_321 && !getdents_321) {/* case 2 */
do_translation = 1;
}
if (do_translation) {
/* We're cutting down the buffer size in two so it's guaranteed we
* have enough space for the translation (data structure has become
* larger).
*/
size = size / 2;
indir_buf_src = malloc(size);
indir_buf_dst = malloc(size * 2); /* dst buffer keeps original size */
if (indir_buf_src == NULL || indir_buf_dst == NULL)
panic("Couldn't allocate temp buf space\n");
grant_id = cpf_grant_direct(fs_e, (vir_bytes) indir_buf_src, size,
CPF_WRITE);
} else if (direct) {
if (direct) {
grant_id = cpf_grant_direct(fs_e, (vir_bytes) buf, size, CPF_WRITE);
} else {
grant_id = cpf_grant_magic(fs_e, who_e, (vir_bytes) buf, size,
@ -368,12 +323,10 @@ int req_getdents(
m.REQ_GRANT = grant_id;
m.REQ_MEM_SIZE = size;
m.REQ_SEEK_POS_LO = ex64lo(pos);
if (VFS_FS_PROTO_BIGOFFT(vmp->m_proto)) {
if (vmp->m_fs_flags & RES_64BIT) {
m.REQ_SEEK_POS_HI = ex64hi(pos);
} else if (pos > INT_MAX) {
/* FS does not support 64-bit off_t and 32 bits is not enough */
if (indir_buf_src != NULL) free(indir_buf_src);
if (indir_buf_dst != NULL) free(indir_buf_dst);
return EINVAL;
} else {
m.REQ_SEEK_POS_HI = 0;
@ -382,23 +335,8 @@ int req_getdents(
r = fs_sendrec(fs_e, &m);
cpf_revoke(grant_id);
if (do_translation) {
if (r == OK) {
m.RES_NBYTES = translate_dents(indir_buf_src, m.RES_NBYTES,
indir_buf_dst, getdents_321);
if (direct) {
memcpy(buf, indir_buf_dst, m.RES_NBYTES);
} else {
r = sys_vircopy(SELF, (vir_bytes) indir_buf_dst, who_e,
(vir_bytes) buf, m.RES_NBYTES);
}
}
free(indir_buf_src);
free(indir_buf_dst);
}
if (r == OK) {
if (VFS_FS_PROTO_BIGOFFT(vmp->m_proto)) {
if (vmp->m_fs_flags & RES_64BIT) {
*new_pos = make64(m.RES_SEEK_POS_LO, m.RES_SEEK_POS_HI);
} else {
*new_pos = m.RES_SEEK_POS_LO;
@ -409,61 +347,6 @@ int req_getdents(
return(r);
}
/*===========================================================================*
* translate_dents *
*===========================================================================*/
static size_t
translate_dents(char *src, size_t size, char *dst, int to_getdents_321)
{
/* Convert between 'struct dirent' and 'struct dirent_321' both ways and
* return the size of the new buffer.
*/
int consumed = 0, newconsumed = 0;
struct dirent *dent;
struct dirent_321 *dent_321;
#define DWORD_ALIGN(d) if((d) % sizeof(long)) (d)+=sizeof(long)-(d)%sizeof(long)
if (to_getdents_321) {
/* Provided format is struct dirent and has to be translated
* to struct dirent_321 */
dent_321 = (struct dirent_321 *) dst;
dent = (struct dirent *) src;
while (consumed < size && dent->d_reclen > 0) {
dent_321->d_ino = (u32_t) dent->d_ino;
dent_321->d_off = (i32_t) dent->d_off;
dent_321->d_reclen = offsetof(struct dirent_321,d_name)+
strlen(dent->d_name) + 1;
DWORD_ALIGN(dent_321->d_reclen);
strcpy(dent_321->d_name, dent->d_name);
consumed += dent->d_reclen;
newconsumed += dent_321->d_reclen;
dent = (struct dirent *) &src[consumed];
dent_321 = (struct dirent_321 *) &dst[newconsumed];
}
} else {
/* Provided format is struct dirent_321 and has to be
* translated to struct dirent */
dent_321 = (struct dirent_321 *) src;
dent = (struct dirent *) dst;
while (consumed < size && dent_321->d_reclen > 0) {
dent->d_ino = (ino_t) dent_321->d_ino;
dent->d_off = (off_t) dent_321->d_off;
dent->d_reclen = offsetof(struct dirent, d_name) +
strlen(dent_321->d_name) + 1;
DWORD_ALIGN(dent->d_reclen);
strcpy(dent->d_name, dent_321->d_name);
consumed += dent_321->d_reclen;
newconsumed += dent->d_reclen;
dent_321 = (struct dirent_321 *) &src[consumed];
dent = (struct dirent *) &dst[newconsumed];
}
}
return newconsumed;
}
/*===========================================================================*
* req_inhibread *
*===========================================================================*/
@ -592,7 +475,7 @@ int req_lookup(
case OK:
res->inode_nr = (ino_t) m.RES_INODE_NR;
res->fmode = (mode_t) m.RES_MODE;
if (VFS_FS_PROTO_BIGOFFT(vmp->m_proto)) {
if (vmp->m_fs_flags & RES_64BIT) {
res->fsize = make64(m.RES_FILE_SIZE_LO, m.RES_FILE_SIZE_HI);
} else {
res->fsize = m.RES_FILE_SIZE_LO;
@ -749,7 +632,7 @@ int req_newnode(
res->fs_e = m.m_source;
res->inode_nr = (ino_t) m.RES_INODE_NR;
res->fmode = (mode_t) m.RES_MODE;
if (VFS_FS_PROTO_BIGOFFT(vmp->m_proto)) {
if (vmp->m_fs_flags & RES_64BIT) {
res->fsize = make64(m.RES_FILE_SIZE_LO, m.RES_FILE_SIZE_HI);
} else {
res->fsize = m.RES_FILE_SIZE_LO;
@ -865,7 +748,8 @@ int req_readsuper(
dev_t dev,
int readonly,
int isroot,
struct node_details *res
struct node_details *res,
unsigned int *fs_flags
)
{
int r;
@ -884,9 +768,6 @@ int req_readsuper(
/* Fill in request message */
m.m_type = REQ_READSUPER;
m.REQ_FLAGS = 0;
m.REQ_PROTO = 0;
VFS_FS_PROTO_PUT_VERSION(m.REQ_PROTO, VFS_FS_CURRENT_VERSION);
m.REQ_FLAGS |= REQ_HASPROTO;
if(readonly) m.REQ_FLAGS |= REQ_RDONLY;
if(isroot) m.REQ_FLAGS |= REQ_ISROOT;
m.REQ_GRANT = grant_id;
@ -901,15 +782,15 @@ int req_readsuper(
/* Fill in response structure */
res->fs_e = m.m_source;
res->inode_nr = (ino_t) m.RES_INODE_NR;
vmp->m_proto = m.RES_PROTO;
res->fmode = (mode_t) m.RES_MODE;
if (VFS_FS_PROTO_BIGOFFT(vmp->m_proto)) {
if (m.RES_FLAGS & RES_64BIT) {
res->fsize = make64(m.RES_FILE_SIZE_LO, m.RES_FILE_SIZE_HI);
} else {
res->fsize = m.RES_FILE_SIZE_LO;
}
res->uid = (uid_t) m.RES_UID;
res->gid = (gid_t) m.RES_GID;
*fs_flags = m.RES_FLAGS;
}
return(r);
@ -947,7 +828,7 @@ unsigned int *cum_iop)
m.REQ_INODE_NR = (pino_t) inode_nr;
m.REQ_GRANT = grant_id;
m.REQ_SEEK_POS_LO = ex64lo(pos);
if (VFS_FS_PROTO_BIGOFFT(vmp->m_proto)) {
if (vmp->m_fs_flags & RES_64BIT) {
m.REQ_SEEK_POS_HI = ex64hi(pos);
} else if (pos > INT_MAX) {
return EINVAL;
@ -962,7 +843,7 @@ unsigned int *cum_iop)
if (r == OK) {
/* Fill in response structure */
if (VFS_FS_PROTO_BIGOFFT(vmp->m_proto)) {
if (vmp->m_fs_flags & RES_64BIT) {
*new_posp = make64(m.RES_SEEK_POS_LO, m.RES_SEEK_POS_HI);
} else {
*new_posp = m.RES_SEEK_POS_LO;

View file

@ -10,14 +10,13 @@ EXTERN struct vmnt {
comm_t m_comm;
dev_t m_dev; /* device number */
unsigned int m_flags; /* mount flags */
unsigned int m_proto; /* vfs-fs protocol info */
unsigned int m_fs_flags; /* capability flags returned by FS */
struct vnode *m_mounted_on; /* vnode on which the partition is mounted */
struct vnode *m_root_node; /* root vnode */
char m_label[LABEL_MAX]; /* label of the file system process */
char m_mount_path[PATH_MAX]; /* path on which vmnt is mounted */
char m_mount_dev[PATH_MAX]; /* device from which vmnt is mounted */
char m_fstype[FSTYPE_MAX]; /* file system type */
int m_haspeek; /* supports REQ_PEEK, REQ_BPEEK */
struct statvfs_cache m_stats; /* cached file system statistics */
} vmnt[NR_MNTS];