#define REQ_FLAGS m6_l3
#define REQ_DEV m6_l3
#define REQ_WHO_E m6_l3
+#define REQ_GRANT m6_l3
#define REQ_USER_ADDR m6_p2
#define REQ_LENGTH m6_l3
#define REQ_SYMLOOP m6_c2
+#define REQ_COUNT m6_l2
#define REQ_NEW_UID m6_s3
#define REQ_NEW_GID m6_c2
#define RES_MODE m6_s1
#define RES_FILE_SIZE m6_l2
#define RES_DEV m6_l3
-#define RES_POS m6_l3
#define RES_INODE_INDEX m6_s2
#define RES_NLINKS m6_s3
#define RES_SYMLOOP m6_c1
#define REQ_WRITE 6
#define REQ_CLONE_OPCL 7
#define REQ_FTRUNC 8
-
#define REQ_CHOWN 9
#define REQ_CHMOD 10
#define REQ_ACCESS 11
#define REQ_MKDIR 13
#define REQ_INHIBREAD 14
#define REQ_STAT 15
-#define REQ_FSTAT 16
+
+#define REQ_CREATE 16
+
#define REQ_UNLINK 17
#define REQ_RMDIR 18
#define REQ_UTIME 19
-#define REQ_FSTATFS 20
-#define REQ_LSTAT 21 /* NO POINT !!! */
-#define REQ_GETDIR 22
+
+#define REQ_FSTATFS 21
#define REQ_LINK 25
#define ELEAVEMOUNT 302
#define ESYMLINK 303
-
-
-
-
-
-
-
-
int direction, int norm));
FORWARD _PROTOTYPE( void new_icopy, (struct inode *rip, d2_inode *dip,
int direction, int norm));
+FORWARD _PROTOTYPE( void put_inode2, (struct inode *rip, int count));
/*===========================================================================*
/* Find the inode specified by the request message and decrease its counter.
*/
struct inode *rip;
+ int count;
/* Sanity check for the direct index */
if (fs_m_in.REQ_INODE_INDEX >= 0 &&
}
if (!rip)
+ {
printf("FSput_inode: inode #%d dev: %d couldn't be put, req_nr: %d\n",
fs_m_in.REQ_INODE_NR, fs_dev, req_nr);
+ panic(__FILE__, "fs_putnode failed", NO_NUM);
+ }
+
+ count= fs_m_in.REQ_COUNT;
+ if (count <= 0)
+ {
+ printf("put_inode: bad value for count: %d\n", count);
+ panic(__FILE__, "fs_putnode failed", NO_NUM);
+ return EINVAL;
+ }
+ if (count > rip->i_count)
+ {
+ printf("put_inode: count too high: %d > %d\n", count, rip->i_count);
+ panic(__FILE__, "fs_putnode failed", NO_NUM);
+ return EINVAL;
+ }
- put_inode(rip);
+ put_inode2(rip, count);
return OK;
}
fs_m_out.RES_MODE = rip->i_mode;
fs_m_out.RES_FILE_SIZE = rip->i_size;
fs_m_out.RES_DEV = (Dev_t) rip->i_zone[0];
+ fs_m_out.RES_UID = rip->i_uid;
+ fs_m_out.RES_GID = rip->i_gid;
return OK;
}
rip->i_count = 1;
if (dev != NO_DEV) rw_inode(rip, READING); /* get inode from disk */
rip->i_update = 0; /* all the times are initially up-to-date */
+ if ((rip->i_mode & I_TYPE) == I_NAMED_PIPE)
+ rip->i_pipe = I_PIPE;
+ else
+ rip->i_pipe = NO_PIPE;
/* Add to hash */
addhash_inode(rip);
if (rip->i_pipe == I_PIPE) truncate_inode(rip, 0);
}
rip->i_mount = NO_MOUNT;
- rip->i_pipe = NO_PIPE; /* should always be cleared */
+ if (rip->i_dirt == DIRTY) rw_inode(rip, WRITING);
+
+ if (rip->i_nlinks == 0) {
+ /* free, put at the front of the LRU list */
+ unhash_inode(rip);
+ rip->i_num = 0;
+ TAILQ_INSERT_HEAD(&unused_inodes, rip, i_unused);
+ }
+ else {
+ /* unused, put at the back of the LRU (cache it) */
+ TAILQ_INSERT_TAIL(&unused_inodes, rip, i_unused);
+ }
+ }
+}
+
+
+/*===========================================================================*
+ * put_inode2 *
+ *===========================================================================*/
+PRIVATE void put_inode2(rip, count)
+register struct inode *rip; /* pointer to inode to be released */
+int count;
+{
+/* The caller is no longer using this inode. If no one else is using it either
+ * write it back to the disk immediately. If it has no links, truncate it and
+ * return it to the pool of available inodes.
+ */
+
+ if (rip == NIL_INODE) return; /* checking here is easier than in caller */
+
+ if (rip->i_count < count)
+ panic(__FILE__, "put_inode2: bad value for count", count);
+ rip->i_count -= count;
+ if (rip->i_count == 0) { /* i_count == 0 means no one is using it now */
+ if (rip->i_nlinks == 0) {
+ /* i_nlinks == 0 means free the inode. */
+ truncate_inode(rip, 0); /* return all the disk blocks */
+ rip->i_mode = I_NOT_ALLOC; /* clear I_TYPE field */
+ rip->i_dirt = DIRTY;
+ free_inode(rip->i_dev, rip->i_num);
+ }
+ else {
+ if (rip->i_pipe == I_PIPE)
+ truncate_inode(rip, 0);
+ }
+ rip->i_mount = NO_MOUNT;
if (rip->i_dirt == DIRTY) rw_inode(rip, WRITING);
if (rip->i_nlinks == 0) {
for (i = 0; i < NR_INODES; ++i) {
if (inode[i].i_count != cch[i] &&
req_nr != REQ_OPEN && req_nr != REQ_GETNODE &&
- req_nr != REQ_PUTNODE && req_nr != REQ_GETDIR &&
+ req_nr != REQ_PUTNODE &&
req_nr != REQ_CLONE_OPCL && req_nr != REQ_READSUPER &&
req_nr != REQ_MOUNTPOINT && req_nr != REQ_UNMOUNT &&
req_nr != REQ_PIPE && req_nr != REQ_SYNC &&
PRIVATE char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0};
FORWARD _PROTOTYPE( struct inode *new_node, (struct inode *ldirp,
- char *string, mode_t bits, zone_t z0, int opaque, char *parsed));
+ char *string, mode_t bits, zone_t z0));
/*===========================================================================*
}
/* Create a new inode by calling new_node(). */
- rip = new_node(ldirp, lastc, omode, NO_ZONE, oflags&O_EXCL, NULL);
+ rip = new_node(ldirp, lastc, omode, NO_ZONE);
r = err_code;
if (r == OK) exist = FALSE; /* we just created the file */
else if (r != EEXIST) {
case I_NAMED_PIPE:
rip->i_pipe = I_PIPE;
- b = (bits & R_BIT ? R_BIT : W_BIT);
- if (b == R_BIT)
- fs_m_out.RES_POS = rip->i_zone[V2_NR_DZONES+0];
- else
- fs_m_out.RES_POS = rip->i_zone[V2_NR_DZONES+1];
break;
}
}
return OK;
}
+/*===========================================================================*
+ * fs_create *
+ *===========================================================================*/
+PUBLIC int fs_create()
+{
+ int r, b;
+ struct inode *ldirp;
+ struct inode *rip;
+ mode_t omode;
+ char lastc[NAME_MAX];
+
+ /* Read request message */
+ omode = fs_m_in.REQ_MODE;
+
+ caller_uid = fs_m_in.REQ_UID;
+ caller_gid = fs_m_in.REQ_GID;
+
+ /* Try to make the file. */
+
+ /* Copy the last component */
+ err_code = sys_datacopy(FS_PROC_NR, (vir_bytes) fs_m_in.REQ_PATH,
+ SELF, (vir_bytes) lastc, (phys_bytes) fs_m_in.REQ_PATH_LEN);
+
+ if (err_code != OK) return err_code;
+
+ /* Get last directory inode */
+ if ((ldirp = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) {
+printf("MFS(%d) get_inode for parent dir by creat() failed\n", SELF_E);
+ return ENOENT;
+ }
+
+ /* Create a new inode by calling new_node(). */
+ rip = new_node(ldirp, lastc, omode, NO_ZONE);
+ r = err_code;
+
+ /* If error, release inode. */
+ if (r != OK) {
+ put_inode(ldirp);
+ put_inode(rip);
+ return(r);
+ }
+
+ /* Reply message */
+ fs_m_out.m_source = rip->i_dev; /* filled with FS endpoint by the system */
+ fs_m_out.RES_INODE_NR = rip->i_num;
+ fs_m_out.RES_MODE = rip->i_mode;
+ fs_m_out.RES_FILE_SIZE = rip->i_size;
+ fs_m_out.RES_INODE_INDEX = (rip - &inode[0]) / sizeof(struct inode);
+
+ /* This values are needed for the execution */
+ fs_m_out.RES_UID = rip->i_uid;
+ fs_m_out.RES_GID = rip->i_gid;
+ if ((rip->i_mode & I_TYPE) == I_REGULAR) fs_m_out.RES_CTIME = rip->i_ctime;
+
+ /* Drop parent dir */
+ put_inode(ldirp);
+
+ return OK;
+}
+
/*===========================================================================*
* fs_mknod *
*===========================================================================*/
}
/* Try to create the new node */
- ip = new_node(ldirp, lastc, fs_m_in.REQ_MODE, (zone_t) fs_m_in.REQ_DEV,
- TRUE, NULL);
+ ip = new_node(ldirp, lastc, fs_m_in.REQ_MODE, (zone_t) fs_m_in.REQ_DEV);
put_inode(ip);
put_inode(ldirp);
}
/* Next make the inode. If that fails, return error code. */
- rip = new_node(ldirp, lastc, fs_m_in.REQ_MODE, (zone_t) 0, TRUE, NULL);
+ rip = new_node(ldirp, lastc, fs_m_in.REQ_MODE, (zone_t) 0);
if (rip == NIL_INODE || err_code == EEXIST) {
put_inode(rip); /* can't make dir: it already exists */
/* Create the inode for the symlink. */
sip = new_node(ldirp, string, (mode_t) (I_SYMBOLIC_LINK | RWX_MODES),
- (zone_t) 0, TRUE, NULL);
+ (zone_t) 0);
/* Allocate a disk block for the contents of the symlink.
* Copy contents of symlink (the name pointed to) into first disk block.
* new_node *
*===========================================================================*/
PRIVATE struct inode *new_node(struct inode *ldirp,
- char *string, mode_t bits, zone_t z0, int opaque, char *parsed)
+ char *string, mode_t bits, zone_t z0)
{
/* New_node() is called by fs_open(), fs_mknod(), and fs_mkdir().
* In all cases it allocates a new inode, makes a directory entry for it in
register struct inode *rip;
register int r;
- /*
- *ldirp = parse_path(path, string, opaque ? LAST_DIR : LAST_DIR_EATSYM);
- if (*ldirp == NIL_INODE) return(NIL_INODE);
- */
-
/* Get final component of the path. */
rip = advance(&ldirp, string);
r = err_code;
}
- if(parsed) { /* Give the caller the parsed string if requested. */
- strncpy(parsed, string, NAME_MAX-1);
- parsed[NAME_MAX-1] = '\0';
- }
-
/* The caller has to return the directory inode (*ldirp). */
err_code = r;
return(rip);
{
char string[NAME_MAX];
struct inode *rip;
- int s_error;
+ int s_error, flags;
string[0] = '\0';
caller_uid = fs_m_in.REQ_UID;
caller_gid = fs_m_in.REQ_GID;
+ flags = fs_m_in.REQ_FLAGS;
+
+ /* Clear RES_OFFSET for ENOENT */
+ fs_m_out.RES_OFFSET= 0;
/* Lookup inode */
- rip = parse_path(user_path, string, fs_m_in.REQ_FLAGS);
+ rip = parse_path(user_path, string, flags);
/* Copy back the last name if it is required */
- if ((fs_m_in.REQ_FLAGS & LAST_DIR || fs_m_in.REQ_FLAGS & LAST_DIR_EATSYM)
- && err_code != ENAMETOOLONG) {
+ if (err_code != OK || (flags & PATH_PENULTIMATE)) {
s_error = sys_datacopy(SELF_E, (vir_bytes) string, FS_PROC_NR,
(vir_bytes) fs_m_in.REQ_USER_ADDR, (phys_bytes)
MIN(strlen(string)+1, NAME_MAX));
/* Error or mount point encountered */
if (rip == NIL_INODE)
- return err_code;
+ {
+ if (err_code != EENTERMOUNT)
+ fs_m_out.RES_INODE_NR = 0; /* signal no inode */
+ return err_code;
+ }
fs_m_out.RES_INODE_NR = rip->i_num;
fs_m_out.RES_MODE = rip->i_mode;
/* Drop inode (path parse increased the counter) */
put_inode(rip);
- return OK;
+ return err_code;
}
printf("FS: couldn't find starting inode req_nr: %d %s\n", req_nr,
user_path);
err_code = ENOENT;
+printf("%s, %d\n", __FILE__, __LINE__);
return NIL_INODE;
}
== NIL_INODE) {
printf("FS: couldn't find chroot inode\n");
err_code = ENOENT;
+printf("%s, %d\n", __FILE__, __LINE__);
return NIL_INODE;
}
}
/* Note: empty (start) path is checked in the VFS process */
if (rip->i_nlinks == 0/* || *path == '\0'*/) {
err_code = ENOENT;
+printf("%s, %d\n", __FILE__, __LINE__);
return(NIL_INODE);
}
if (rip->i_mount == I_MOUNT && rip->i_num != ROOT_INODE) {
dir_ip = rip;
rip = advance(&dir_ip, "..");
- if (rip == NIL_INODE) return rip;
+ if (rip == NIL_INODE)
+ {
+printf("%s, %d\n", __FILE__, __LINE__);
+ return NIL_INODE;
+ }
put_inode(rip); /* advance() increased the counter */
}
/* Scan the path component by component. */
while (TRUE) {
/* Extract one component. */
+ fs_m_out.RES_OFFSET = path_processed; /* For ENOENT */
if ( (new_name = get_name(path, string)) == (char*) 0) {
put_inode(rip); /* bad path in user space */
+printf("%s, %d\n", __FILE__, __LINE__);
return(NIL_INODE);
}
if (*new_name == '\0' && (action & PATH_PENULTIMATE)) {
/* last file of path prefix is not a directory */
put_inode(rip);
err_code = ENOTDIR;
+printf("%s, %d\n", __FILE__, __LINE__);
return(NIL_INODE);
}
}
if (rip == NIL_INODE) {
if (*new_name == '\0' && (action & PATH_NONSYMBOLIC) != 0)
+ {
+printf("%s, %d\n", __FILE__, __LINE__);
return(dir_ip);
+ }
+ else if (err_code == ENOENT)
+ {
+ return(dir_ip);
+ }
else {
put_inode(dir_ip);
+printf("%s, %d\n", __FILE__, __LINE__);
return(NIL_INODE);
}
}
if (ltraverse(rip, user_path, new_name) != OK) {
put_inode(dir_ip);
err_code = ENOENT;
+printf("%s, %d\n", __FILE__, __LINE__);
return NIL_INODE;
}
if (++symloop > SYMLOOP) {
put_inode(dir_ip);
err_code = ELOOP;
+printf("%s, %d\n", __FILE__, __LINE__);
return NIL_INODE;
}
/* Either last name reached or symbolic link is opaque */
if ((action & PATH_NONSYMBOLIC) != 0) {
put_inode(rip);
+printf("%s, %d\n", __FILE__, __LINE__);
return(dir_ip);
} else {
put_inode(dir_ip);
int fs_mkdir(void);
int fs_inhibread(void);
int fs_stat(void);
-int fs_fstat(void);
+int fs_create(void);
int fs_unlink(void);
int fs_utime(void);
int fs_fstatfs(void);
-int fs_lstat(void);
-int fs_getdir(void);
int fs_link(void);
int fs_lookup_rn_old(void);
int fs_lookup_rn_new(void);
FORWARD _PROTOTYPE( int stat_inode, (struct inode *rip, int pipe_pos,
- char *user_addr, int who_e) );
+ int who_e, cp_grant_id_t gid) );
-/*===========================================================================*
- * fs_getdir *
- *===========================================================================*/
-PUBLIC int fs_getdir()
-{
- register int r;
- register struct inode *rip;
-
- struct inodelist *rlp;
-
- caller_uid = fs_m_in.REQ_UID;
- caller_gid = fs_m_in.REQ_GID;
-
- /* Try to open the new directory. */
- if ( (rip = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) {
-printf("MFS(%d) get_inode by fs_getdir() failed\n", SELF_E);
- return(EINVAL);
- }
-
- r = forbidden(rip, X_BIT); /* check if dir is searchable */
-
- /* If error, return inode. */
- if (r != OK) {
- put_inode(rip);
- return(r);
- }
-
- /* If OK send back inode details */
- fs_m_out.m_source = rip->i_dev; /* filled with FS endpoint by the system */
- fs_m_out.RES_INODE_NR = rip->i_num;
- fs_m_out.RES_MODE = rip->i_mode;
- fs_m_out.RES_FILE_SIZE = rip->i_size;
-
-/*
-printf("MFS(%d): ", SELF_E);
-for (rlp = &hash_inodes[0]; rlp < &hash_inodes[INODE_HASH_SIZE]; ++rlp) {
- int elements = 0;
- LIST_FOREACH(rip, rlp, i_hash) elements++;
- printf("%d ", elements);
-}
-printf("\n");
-*/
-
- return OK;
-}
-
-/*===========================================================================*
- * fs_stat *
- *===========================================================================*/
-PUBLIC int fs_stat()
-{
- register struct inode *rip;
- register int r;
-
- /* Both stat() and fstat() use the same routine to do the real work. That
- * routine expects an inode, so acquire it temporarily.
- */
- caller_uid = fs_m_in.REQ_UID;
- caller_gid = fs_m_in.REQ_GID;
-
- if ( (rip = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) {
-printf("MFS(%d) get_inode by fs_stat() failed\n", SELF_E);
- return(EINVAL);
- }
-
- r = stat_inode(rip, 0, fs_m_in.REQ_USER_ADDR, fs_m_in.REQ_WHO_E);
- put_inode(rip); /* release the inode */
- return(r);
-}
-
-
-/*===========================================================================*
- * fs_fstat *
- *===========================================================================*/
-PUBLIC int fs_fstat()
-{
- int r;
- struct inode *rip;
-
- /* Both stat() and fstat() use the same routine to do the real work. That
- * routine expects an inode, so acquire it temporarily.
- */
- if ((rip = find_inode(fs_dev, fs_m_in.REQ_FD_INODE_NR))
- == NIL_INODE) {
- printf("FSfstat: couldn't find inode %d\n", fs_m_in.REQ_FD_INODE_NR);
- return EINVAL;
- }
-
- r = stat_inode(rip, fs_m_in.REQ_FD_POS, fs_m_in.REQ_FD_USER_ADDR,
- fs_m_in.REQ_FD_WHO_E);
-
- return r;
-}
-
/*===========================================================================*
* stat_inode *
*===========================================================================*/
-PRIVATE int stat_inode(rip, pipe_pos, user_addr, who_e)
+PRIVATE int stat_inode(rip, pipe_pos, who_e, gid)
register struct inode *rip; /* pointer to inode to stat */
int pipe_pos; /* position in a pipe, supplied by fstat() */
-char *user_addr; /* user space address where stat buf goes */
-int who_e; /* kernel endpoint of the caller */
+int who_e; /* Caller endpoint */
+cp_grant_id_t gid; /* grant for the stat buf */
{
/* Common code for stat and fstat system calls. */
statbuf.st_ctime = rip->i_ctime;
/* Copy the struct to user space. */
- r = sys_datacopy(SELF, (vir_bytes) &statbuf,
- who_e, (vir_bytes) user_addr, (phys_bytes) sizeof(statbuf));
+ r = sys_safecopyto(who_e, gid, 0, (vir_bytes) &statbuf,
+ (phys_bytes) sizeof(statbuf), D);
return(r);
}
-
/*===========================================================================*
* fs_fstatfs *
*===========================================================================*/
struct statfs st;
struct inode *rip;
int r;
-
+
if ((rip = find_inode(fs_dev, fs_m_in.REQ_FD_INODE_NR))
== NIL_INODE) {
printf("FSfstatfs: couldn't find inode %d\n", fs_m_in.REQ_FD_INODE_NR);
st.f_bsize = rip->i_sp->s_block_size;
/* Copy the struct to user space. */
- r = sys_datacopy(SELF, (vir_bytes) &st, fs_m_in.REQ_FD_WHO_E,
- (vir_bytes) fs_m_in.REQ_FD_USER_ADDR, (phys_bytes) sizeof(st));
+ r = sys_safecopyto(fs_m_in.m_source, fs_m_in.REQ_GRANT, 0,
+ (vir_bytes) &st, (phys_bytes) sizeof(st), D);
return(r);
}
/*===========================================================================*
- * fs_lstat *
+ * fs_stat *
*===========================================================================*/
-PUBLIC int fs_lstat()
+PUBLIC int fs_stat()
{
register int r; /* return value */
register struct inode *rip; /* target inode */
- caller_uid = fs_m_in.REQ_UID;
- caller_gid = fs_m_in.REQ_GID;
if ( (rip = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) {
-printf("MFS(%d) get_inode by fs_lstat() failed\n", SELF_E);
+printf("MFS(%d) get_inode by fs_stat() failed\n", SELF_E);
return(EINVAL);
}
- r = stat_inode(rip, 0, fs_m_in.REQ_USER_ADDR, fs_m_in.REQ_WHO_E);
+ r = stat_inode(rip, 0, fs_m_in.m_source, fs_m_in.REQ_GRANT);
put_inode(rip); /* release the inode */
return(r);
}
fs_mkdir, /* 13 */
fs_inhibread, /* 14 */ /* for lseek() */
fs_stat, /* 15 */
- fs_fstat, /* 16 */
+ fs_create, /* 16 */
fs_unlink, /* 17 */ /* unlink() */
fs_unlink, /* 18 */ /* rmdir() */
fs_utime, /* 19 */
- fs_fstatfs, /* 20 */
- fs_lstat, /* 21 */
- fs_getdir, /* 22 */ /* chdir(), chroot() */
-
+ no_sys, /* 20 */
+ fs_fstatfs, /* 21 */
+ no_sys, /* 22 */
no_sys, /* 23 */
no_sys, /* 24 */
fs_link, /* 25 */
&& (vp->v_mode & I_TYPE) != I_BLOCK_SPECIAL) return(ENOTTY);
dev = (dev_t) vp->v_sdev;
- return(dev_io(DEV_IOCTL, dev, who_e, m_in.ADDRESS, cvu64(0),
+ return (dev_io(DEV_IOCTL, dev, who_e, m_in.ADDRESS, cvu64(0),
m_in.REQUEST, f->filp_flags));
}
vp = fp->fp_filp[m_in.fd]->filp_vno;
put_vnode(vp);
- if ((vp = get_free_vnode()) == NIL_VNODE) {
+ if ((vp = get_free_vnode(__FILE__, __LINE__)) == NIL_VNODE) {
printf("VFSclone_opcl: failed to get a free vnode..\n");
vp = fp->fp_filp[m_in.fd]->filp_vno;
}
vp->v_inode_nr = res.inode_nr;
vp->v_mode = res.fmode;
vp->v_sdev = dev;
- vp->v_count = 1;
+ vp->v_fs_count = 1;
+ vp->v_ref_count = 1;
fp->fp_filp[m_in.fd]->filp_vno = vp;
}
dev_mess.REP_STATUS = OK;
uid_t new_uid;
gid_t new_gid;
struct fproc *rfp;
- struct vnode vn;
- struct vmnt *vmp;
+ struct vnode *vp;
time_t v_ctime;
- uid_t v_uid;
- gid_t v_gid;
char *cp;
+ struct stat sb;
char progname[PROC_NAME_LEN];
static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */
/* Request and response structures */
struct lookup_req lookup_req;
- struct access_req access_req;
- struct open_req open_req;
- struct node_details res;
+ struct node_details Xres;
okendpt(proc_e, &proc_s);
rfp= fp= &fproc[proc_s];
if (r != OK)
{
printf("pm_exec: fetch_name failed\n");
+printf("return at %s, %d\n", __FILE__, __LINE__);
return(r); /* file name not in user data segment */
}
if (frame_len > ARG_MAX)
{
printf("pm_exec: bad frame_len\n");
+printf("return at %s, %d\n", __FILE__, __LINE__);
return(ENOMEM); /* stack too big */
}
r = sys_datacopy(proc_e, (vir_bytes) frame,
if (r != OK)
{
printf("pm_exec: sys_datacopy failed\n");
+printf("return at %s, %d\n", __FILE__, __LINE__);
return(r);
}
lookup_req.flags = EAT_PATH;
/* Request lookup */
- if ((r = lookup(&lookup_req, &res)) != OK) return r;
+ if ((r = lookup_vp(&lookup_req, &vp)) != OK)
+ {
+ put_vnode(vp);
+ return r;
+ }
- if ((res.fmode & I_TYPE) != I_REGULAR) {
+ if ((vp->v_mode & I_TYPE) != I_REGULAR) {
+printf("put_vnode at %s, %d\n", __FILE__, __LINE__);
+ put_vnode(vp);
+printf("return at %s, %d\n", __FILE__, __LINE__);
return ENOEXEC;
}
- else {
- /* Fill in request fields */
- access_req.fs_e = res.fs_e;
- access_req.amode = X_BIT;
- access_req.inode_nr = res.inode_nr;
- access_req.uid = fp->fp_effuid;
- access_req.gid = fp->fp_effgid;
-
-
- /* Issue request */
- if ((r = req_access(&access_req)) != OK) {
- printf("VFSexec: access failed for %s\n", progname);
- return r;
- }
- }
- /* Open request. */
- open_req.inode_nr = res.inode_nr;
- open_req.fs_e = res.fs_e;
- open_req.oflags = 0;
- open_req.omode = 0;
- open_req.lastc = NULL;
- open_req.uid = 0;
- open_req.gid = 0;
-
- /* Issue request */
- if ((r = req_open(&open_req, &res)) != OK) {
- printf("VFSexec: open failed\n");
+ /* Check access. */
+ if ((r = forbidden(vp, X_BIT)) != OK)
+ {
+printf("put_vnode at %s, %d\n", __FILE__, __LINE__);
+ put_vnode(vp);
+printf("return at %s, %d\n", __FILE__, __LINE__);
return r;
}
- /* Use the vnode to store file details */
- vn.v_inode_nr = res.inode_nr;
- vn.v_mode = res.fmode;
- vn.v_index = res.inode_index;
- vn.v_size = res.fsize;
- vn.v_fs_e = res.fs_e;
- vn.v_count = 1;
- if ( (vmp = find_vmnt(vn.v_fs_e)) == NIL_VMNT)
- printf("VFS: vmnt not found by exec()");
-
- vn.v_dev = vmp->m_dev;
- vn.v_vmnt = vmp;
-
- v_ctime = res.ctime;
- v_uid = res.uid;
- v_gid = res.gid;
+ /* Get ctime */
+ r= req_stat(vp->v_fs_e, vp->v_inode_nr, FS_PROC_NR, (char *)&sb, 0);
+ if (r != OK)
+ {
+ put_vnode(vp);
+ return r;
+ }
+ v_ctime = sb.st_ctime;
if (round == 0)
{
/* Deal with setuid/setgid executables */
- if (vn.v_mode & I_SET_UID_BIT)
- new_uid = v_uid;
- if (vn.v_mode & I_SET_GID_BIT)
- new_gid = v_gid;
+ if (vp->v_mode & I_SET_UID_BIT)
+ new_uid = vp->v_uid;
+ if (vp->v_mode & I_SET_GID_BIT)
+ new_gid = vp->v_gid;
}
/* Read the file header and extract the segment sizes. */
- r = read_header(&vn, &sep_id, &text_bytes, &data_bytes, &bss_bytes,
+ r = read_header(vp, &sep_id, &text_bytes, &data_bytes, &bss_bytes,
&tot_bytes, &pc, &hdrlen);
if (r != ESCRIPT || round != 0)
break;
if (r != OK)
{
printf("pm_exec: 2nd fetch_name failed\n");
- put_vnode(&vn);
+printf("put_vnode at %s, %d\n", __FILE__, __LINE__);
+ put_vnode(vp);
+printf("return at %s, %d\n", __FILE__, __LINE__);
return(r); /* strange */
}
- r= patch_stack(&vn, mbuf, &frame_len);
- put_vnode(&vn);
+ r= patch_stack(vp, mbuf, &frame_len);
+ put_vnode(vp);
if (r != OK)
{
printf("pm_exec: patch stack\n");
+printf("return at %s, %d\n", __FILE__, __LINE__);
return r;
}
}
if (r != OK)
{
printf("pm_exec: returning ENOEXEC, r = %d\n", r);
+ printf("pm_exec: progname = '%s'\n", progname);
+ put_vnode(vp);
return ENOEXEC;
}
r= exec_newmem(proc_e, text_bytes, data_bytes, bss_bytes, tot_bytes,
- frame_len, sep_id, vn.v_dev, vn.v_inode_nr, v_ctime,
+ frame_len, sep_id, vp->v_dev, vp->v_inode_nr, v_ctime,
progname, new_uid, new_gid, &stack_top, &load_text, &allow_setuid);
if (r != OK)
{
printf("pm_exec: exec_newmap failed: %d\n", r);
- put_vnode(&vn);
+printf("put_vnode at %s, %d\n", __FILE__, __LINE__);
+ put_vnode(vp);
+printf("return at %s, %d\n", __FILE__, __LINE__);
return r;
}
/* Read in text and data segments. */
if (load_text) {
- r= read_seg(&vn, off, proc_e, T, text_bytes);
+ r= read_seg(vp, off, proc_e, T, text_bytes);
}
off += text_bytes;
if (r == OK)
- r= read_seg(&vn, off, proc_e, D, data_bytes);
+ r= read_seg(vp, off, proc_e, D, data_bytes);
- put_vnode(&vn);
+ put_vnode(vp);
- if (r != OK) return r;
+ if (r != OK)
+ {
+printf("return at %s, %d\n", __FILE__, __LINE__);
+ return r;
+ }
clo_exec(rfp);
struct lookup_req lookup_req;
struct node_details res;
int r;
+
+ printf("in do_truncate\n");
if (fetch_name(m_in.m2_p1, m_in.m2_i1, M1) != OK) return err_code;
PUBLIC int do_ftruncate()
{
/* As with do_truncate(), truncate_inode() does the actual work. */
- int r;
struct filp *rfilp;
- struct ftrunc_req req;
if ( (rfilp = get_filp(m_in.m2_i1)) == NIL_FILP)
return err_code;
- if ( (rfilp->filp_vno->v_mode & I_TYPE) != I_REGULAR)
+ return truncate_vn(rfilp->filp_vno, m_in.m2_l1);
+}
+
+
+/*===========================================================================*
+ * truncate_vn *
+ *===========================================================================*/
+PUBLIC int truncate_vn(vp, newsize)
+struct vnode *vp;
+off_t newsize;
+{
+ int r;
+ struct ftrunc_req req;
+
+ if ( (vp->v_mode & I_TYPE) != I_REGULAR &&
+ (vp->v_mode & I_TYPE) != I_NAMED_PIPE) {
return EINVAL;
+ }
/* Fill in FS request */
- req.fs_e = rfilp->filp_vno->v_fs_e;
- req.inode_nr = rfilp->filp_vno->v_inode_nr;
- req.start = m_in.m2_l1;
+ req.fs_e = vp->v_fs_e;
+ req.inode_nr = vp->v_inode_nr;
+ req.start = newsize;
req.end = 0; /* Indicate trunc in fs_freesp_trunc */
/* Issue request */
if ((r = req_ftrunc(&req)) != OK) return r;
- rfilp->filp_vno->v_size = m_in.m2_l1;
+ vp->v_size = newsize;
return OK;
}
fs_init();
-
/* This is the main loop that gets work, processes it, and sends replies. */
while (TRUE) {
get_work(); /* sets who and call_nr */
/* Device notifies us of an event. */
dev_status(&m_in);
}
+#if 0
+ if (!check_vrefs())
+ {
+ printf("after call %d from %d/%d\n",
+ call_nr, who_p, who_e);
+ panic(__FILE__, "check_vrefs failed at line", __LINE__);
+ }
+#endif
continue;
}
if (error != SUSPEND) { reply(who_e, error); }
}
+#if 0
+ if (!check_vrefs())
+ {
+ printf("after call %d from %d/%d\n", call_nr, who_p, who_e);
+ panic(__FILE__, "check_vrefs failed at line", __LINE__);
+ }
+#endif
}
return(OK); /* shouldn't come here */
}
FD_ZERO(&(rfp->fp_filp_inuse));
if (rfp->fp_pid != PID_FREE) {
- rfp->fp_rd = get_vnode(ROOT_FS_E, ROOT_INODE);
- rfp->fp_wd = get_vnode(ROOT_FS_E, ROOT_INODE);
+ rfp->fp_rd = get_vnode_x(ROOT_FS_E, ROOT_INODE);
+ rfp->fp_wd = get_vnode_x(ROOT_FS_E, ROOT_INODE);
} else rfp->fp_endpoint = NONE;
}
vmp = &vmnt[0];
/* We'll need a vnode for the root inode, check whether there is one */
- if ((root_node = get_free_vnode()) == NIL_VNODE) {
+ if ((root_node = get_free_vnode(__FILE__, __LINE__)) == NIL_VNODE) {
panic(__FILE__,"Cannot get free vnode", r);
}
root_node->v_mode = sres.fmode;
root_node->v_size = sres.fsize;
root_node->v_sdev = NO_DEV;
- root_node->v_count = 1;
+ root_node->v_fs_count = 0; /* Is this correct? */
+ root_node->v_ref_count = 1;
/* Fill in max file size and blocksize for the vmnt */
vmp->m_fs_e = sres.fs_e;
/* Root directory is mounted on itself */
vmp->m_mounted_on = root_node;
+ root_node->v_ref_count++;
vmp->m_root_node = root_node;
}
put_vnode(vmnt[0].m_mounted_on);
vmnt[0].m_mounted_on = &vdummy;
vmnt[0].m_root_node = &vdummy;
- vdummy.v_count = 1;
+ vdummy.v_fs_count = 0; /* Is this right? */
+ vdummy.v_ref_count = 1;
/* Unmount all filesystems. File systems are mounted on other file systems,
* so you have to pull off the loose bits repeatedly to get it all undone.
struct readsuper_req sreq;
struct readsuper_res sres;
struct lookup_req lookup_req;
+ node_req_t node_req;
/* Only the super-user may do MOUNT. */
if (!super_user) return(EPERM);
if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
/* Get free vnode for the mountpoint */
- if ((mounted_on = get_free_vnode()) == NIL_VNODE) {
+ if ((mounted_on = get_free_vnode(__FILE__, __LINE__)) == NIL_VNODE) {
printf("VFSmount: not free vnode available\n");
return ENFILE;
}
/* Mark it as used so that we won't find the same for the root_node */
- mounted_on->v_count = 1;
+ mounted_on->v_ref_count = 1;
/* Convert name to device number */
if ((dev = name_to_dev()) == NO_DEV) return(err_code);
/* Check whether there is a block special file open which uses the
* same device (partition) */
for (bspec = &vnode[0]; bspec < &vnode[NR_VNODES]; ++bspec) {
- if (bspec->v_count > 0 && bspec->v_sdev == dev) {
+ if (bspec->v_ref_count > 0 && bspec->v_sdev == dev) {
/* Found, sync the buffer cache */
req_sync(bspec->v_fs_e);
break;
* vnodes are different or if the root of FS is equal two the
* root of the filesystem we found, we found a filesystem that
* is in use. */
- mounted_on->v_count = 0;
+ mounted_on->v_ref_count = 0;
return EBUSY; /* already mounted */
}
mounted_on->v_mode = res.fmode;
mounted_on->v_size = res.fsize;
mounted_on->v_sdev = NO_DEV;
- mounted_on->v_count = 1;
+ mounted_on->v_fs_count = 1;
+ mounted_on->v_ref_count = 1;
/* Find the vmnt for the vnode */
if ( (vmp2 = find_vmnt(mounted_on->v_fs_e)) == NIL_VMNT)
}
/* We'll need a vnode for the root inode, check whether there is one */
- if ((root_node = get_free_vnode()) == NIL_VNODE) {
+ if ((root_node = get_free_vnode(__FILE__, __LINE__)) == NIL_VNODE) {
printf("VFSmount: no free vnode available\n");
return ENFILE;
}
/* Set it back to zero so that if st goes wrong it won't be kept in use */
- mounted_on->v_count = 0;
+ mounted_on->v_ref_count = 0;
/* Fetch the name of the mountpoint */
if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) {
return r;
}
+ /* Fill in request message fields.*/
+ node_req.fs_e = sres.fs_e;
+ node_req.inode_nr = sres.inode_nr;
+
+ /* Issue request */
+ if ((r = req_getnode(&node_req, &res)) != OK)
+ {
+ printf("mount: req_getnode failed: %d\n", r);
+ dev_close(dev);
+ return r;
+ }
+
/* Fill in root node's fields */
- root_node->v_fs_e = sres.fs_e;
- root_node->v_inode_nr = sres.inode_nr;
- root_node->v_mode = sres.fmode;
- root_node->v_size = sres.fsize;
+ root_node->v_fs_e = res.fs_e;
+ root_node->v_inode_nr = res.inode_nr;
+ root_node->v_mode = res.fmode;
+ root_node->v_uid = res.uid;
+ root_node->v_gid = res.gid;
+ root_node->v_size = res.fsize;
root_node->v_sdev = NO_DEV;
- root_node->v_count = 1;
+ root_node->v_fs_count = 2;
+ root_node->v_ref_count = 1;
/* Fill in max file size and blocksize for the vmnt */
vmp->m_fs_e = sres.fs_e;
/* Superblock and root node already read.
* Nothing else can go wrong. Perform the mount. */
vmp->m_root_node = root_node;
+ root_node->v_ref_count++;
vmp->m_mounted_on = root_node;
root_dev = dev;
ROOT_FS_E = fs_e;
mounted_on->v_mode = res.fmode;
mounted_on->v_size = res.fsize;
mounted_on->v_sdev = NO_DEV;
- mounted_on->v_count = 1;
+ mounted_on->v_fs_count = 1;
+ mounted_on->v_ref_count = 1;
/* Find the vmnt for the vnode */
if ( (vmp2 = find_vmnt(mounted_on->v_fs_e)) == NIL_VMNT)
*/
count = 0;
for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; vp++) {
- if (vp->v_count > 0 && vp->v_dev == dev) {
- count += vp->v_count;
+ if (vp->v_ref_count > 0 && vp->v_dev == dev) {
+ count += vp->v_ref_count;
}
}
return(EBUSY); /* can't umount a busy file system */
}
+ vnode_clean_refs(vmp->m_root_node);
+
/* Request FS the unmount */
if ((r = req_unmount(vmp->m_fs_e)) != OK) return r;
/* Root device is mounted on itself */
if (vmp->m_root_node != vmp->m_mounted_on) {
put_vnode(vmp->m_mounted_on);
- vmp->m_root_node->v_count = 0;
+ vmp->m_root_node->v_ref_count = 0;
}
else {
- vmp->m_mounted_on->v_count--;
+ vmp->m_mounted_on->v_fs_count--;
}
fs_e = vmp->m_fs_e;
#define offset_lo m2_l1
#define offset_high m2_l2
-
+FORWARD _PROTOTYPE( int x_open, (int bits, int oflags, int omode,
+ char *lastc, struct vnode **vpp) );
FORWARD _PROTOTYPE( int common_open, (int oflags, mode_t omode) );
FORWARD _PROTOTYPE( int pipe_open, (struct vnode *vp,mode_t bits,int oflags));
struct filp *fil_ptr, *filp2;
struct vnode *vp, *vp2;
struct vmnt *vmp;
- char lastc[NAME_MAX];
+ char Xlastc[NAME_MAX];
+ char *pathrem;
int m;
/* Request and response structures */
- struct lookup_req lookup_req;
- struct open_req req;
- struct node_details res;
+ struct lookup_req Xlookup_req;
+ struct open_req Xreq;
/* Remap the bottom two bits of oflags. */
m = oflags & O_ACCMODE;
/* See if file descriptor and filp slots are available. */
if ((r = get_fd(0, bits, &m_in.fd, &fil_ptr)) != OK) return(r);
- /* See if a free vnode is available */
- if ((vp = get_free_vnode()) == NIL_VNODE) {
- printf("VFS: no vnode available!\n");
- return err_code;
- }
-
/* If O_CREATE, set umask */
if (oflags & O_CREAT) {
omode = I_REGULAR | (omode & ALL_MODES & fp->fp_umask);
}
+ vp= NULL;
+
+#if 0
+ printf("common_open: for '%s'\n", user_fullpath);
+#endif
+
/* Fill in lookup request fields */
- lookup_req.path = user_fullpath;
- lookup_req.lastc = lastc;
- lookup_req.flags = oflags&O_CREAT ? (oflags&O_EXCL ? LAST_DIR :
+ Xlookup_req.path = user_fullpath;
+ Xlookup_req.lastc = Xlastc;
+ Xlookup_req.flags = oflags&O_CREAT ? (oflags&O_EXCL ? LAST_DIR :
LAST_DIR_EATSYM) : EAT_PATH;
+ Xlookup_req.flags = ((oflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) ?
+ LAST_DIR : EAT_PATH;
+ Xlastc[0]= '\0'; /* Clear lastc, it will be filled with the part of the
+ * path that cannot be resolved.
+ */
/* Request lookup */
- if ((r = lookup(&lookup_req, &res)) != OK) return r;
+ r = Xlookup_vp(&Xlookup_req, &vp, &pathrem);
+
+ if (r == OK && ((oflags & (O_CREAT|O_EXCL)) != (O_CREAT|O_EXCL)))
+ {
+ /* Clear lastc */
+ Xlastc[0]= '\0';
+ }
+ /* Hide ENOENT for O_CREAT */
+ if (r == ENOENT && (oflags & O_CREAT))
+ {
+ if (pathrem == NULL)
+ panic(__FILE__, "no pathrem", NO_NUM);
+ if (strchr(pathrem, '/') == 0)
+ r= OK;
+ else
+ {
+ printf("common_open: / in pathrem");
+ }
+ }
+
+ if (r != OK)
+ {
+ if (vp)
+ {
+ put_vnode(vp);
+ vp= NULL;
+ }
+ return r;
+ }
+
+ if (!vp) panic(__FILE__, "common_open: no vp", NO_NUM);
+
+ r= x_open(bits, oflags, omode, Xlastc, &vp);
+ if (r != OK)
+ {
+ if (vp)
+ {
+ put_vnode(vp);
+ vp= NULL;
+ }
+ return r;
+ }
+
+#if 0
/* Lookup was okay, fill in request fields for
* the actual open request. */
req.inode_nr = res.inode_nr;
/* Check whether the vnode is already in use */
if ((vp2 = find_vnode(res.fs_e, res.inode_nr)) != NIL_VNODE) {
vp = vp2;
- vp->v_size = res.fsize;; /* In case of trunc... */
- vp->v_count++;
+ vp->v_size = res.fsize; /* In case of trunc... */
+ vp->v_ref_count++;
+ vp->v_fs_count++;
}
/* Otherwise use the free one */
else {
vp->v_dev = vmp->m_dev;
vp->v_inode_nr = res.inode_nr;
vp->v_mode = res.fmode;
+ vp->v_uid = res.uid;
+ vp->v_gid = res.gid;
vp->v_size = res.fsize;
vp->v_sdev = res.dev;
- vp->v_count = 1;
+ vp->v_fs_count = 1;
+ vp->v_ref_count = 1;
vp->v_vmnt = vmp;
vp->v_index = res.inode_index;
}
+#endif
/* Claim the file descriptor and filp slot and fill them in. */
fp->fp_filp[m_in.fd] = fil_ptr;
fil_ptr->filp_flags = oflags;
fil_ptr->filp_vno = vp;
+ vp->v_isfifo= FALSE;
switch (vp->v_mode & I_TYPE) {
case I_CHAR_SPECIAL:
/* Invoke the driver for special processing. */
case I_BLOCK_SPECIAL:
/* Invoke the driver for special processing. */
r = dev_open(vp->v_sdev, who_e, bits | (oflags & ~O_ACCMODE));
+ if (r != OK)
+ panic(__FILE__, "common_open: dev_open failed", r);
/* Check whether the device is mounted or not */
found = 0;
break;
case I_NAMED_PIPE:
+ printf("common_open: setting I_PIPE, inode %d on dev 0x%x\n",
+ vp->v_inode_nr, vp->v_dev);
vp->v_pipe = I_PIPE;
+ vp->v_isfifo= TRUE;
oflags |= O_APPEND; /* force append mode */
fil_ptr->filp_flags = oflags;
r = pipe_open(vp, bits, oflags);
return(m_in.fd);
}
+/*===========================================================================*
+ * x_open *
+ *===========================================================================*/
+PRIVATE int x_open(bits, oflags, omode, lastc, vpp)
+mode_t bits;
+int oflags;
+mode_t omode;
+char *lastc;
+struct vnode **vpp;
+{
+ int r, b, exist = TRUE;
+ struct vnode *vp, *dvp, *tmp_vp;
+ struct vmnt *vmp;
+ struct node_details res;
+
+ /* If O_CREATE is set, try to make the file. */
+ if ((oflags & O_CREAT) && lastc[0] != '\0') {
+ dvp= *vpp; /* Parent directory */
+
+ /* See if a free vnode is available */
+ if ((vp = get_free_vnode(__FILE__, __LINE__)) == NIL_VNODE) {
+ printf("VFS x_open: no free vnode available\n");
+ return EINVAL;
+ }
+
+ r= req_create(dvp->v_fs_e, dvp->v_inode_nr, omode, fp->fp_effuid,
+ fp->fp_effgid, lastc, &res);
+ if (r != OK)
+ return r;
+ exist = FALSE;
+
+ /* Check whether vnode is already in use or not */
+ if ((tmp_vp = find_vnode(res.fs_e, res.inode_nr)) != NIL_VNODE) {
+ vp= tmp_vp;
+ vp->v_ref_count++;
+ vp->v_fs_count++;
+ }
+ else
+ {
+ /* Fill in the free vnode's fields */
+ vp->v_fs_e = res.fs_e;
+ vp->v_inode_nr = res.inode_nr;
+ vp->v_mode = res.fmode;
+ vp->v_size = res.fsize;
+ vp->v_uid = res.uid;
+ vp->v_gid = res.gid;
+ vp->v_sdev = res.dev;
+
+ if ( (vmp = find_vmnt(vp->v_fs_e)) == NIL_VMNT)
+ panic(__FILE__, "lookup_vp: vmnt not found", NO_NUM);
+
+ vp->v_vmnt = vmp;
+ vp->v_dev = vmp->m_dev;
+ vp->v_fs_count = 1;
+ vp->v_ref_count = 1;
+ }
+
+ /* Release dvp */
+ put_vnode(dvp);
+
+ /* Update *vpp */
+ *vpp= vp;
+ }
+ else {
+ vp= *vpp;
+ }
+
+ /* Only do the normal open code if we didn't just create the file. */
+ if (!exist)
+ return OK;
+
+ /* Check protections. */
+ if ((r = forbidden(vp, bits)) != OK)
+ return r;
+
+ /* Opening reg. files directories and special files differ. */
+ switch (vp->v_mode & I_TYPE) {
+ case I_REGULAR:
+ /* Truncate regular file if O_TRUNC. */
+ if (oflags & O_TRUNC) {
+ if ((r = forbidden(vp, W_BIT)) !=OK) break;
+ truncate_vn(vp, 0);
+ }
+ break;
+
+ case I_DIRECTORY:
+ /* Directories may be read but not written. */
+ r = (bits & W_BIT ? EISDIR : OK);
+ break;
+
+ case I_CHAR_SPECIAL:
+ case I_BLOCK_SPECIAL:
+ if (vp->v_sdev == (dev_t)-1)
+ panic(__FILE__, "x_open: bad special", NO_NUM);
+ break;
+
+ case I_NAMED_PIPE:
+ printf("x_open (fifo): reference count %d, fd %d\n",
+ vp->v_ref_count, vp->v_fs_count);
+ if (vp->v_ref_count == 1)
+ {
+ printf("x_open (fifo): first reference, size %u\n",
+ vp->v_size);
+ if (vp->v_size != 0)
+ {
+ printf("x_open (fifo): clearing\n");
+ r= truncate_vn(vp, 0);
+ if (r != OK)
+ {
+ printf(
+ "x_open (fifo): truncate_vn failed: %d\n",
+ r);
+ }
+ }
+ }
+ break;
+ }
+
+ return(r);
+}
/*===========================================================================*
* processes hanging on the pipe.
*/
+ printf("pipe_open: setting I_PIPE, inode %d on dev 0x%x\n",
+ vp->v_inode_nr, vp->v_dev);
vp->v_pipe = I_PIPE;
if((bits & (R_BIT|W_BIT)) == (R_BIT|W_BIT)) {
/* If a write has been done, the inode is already marked as DIRTY. */
if (--rfilp->filp_count == 0) {
- if (vp->v_pipe == I_PIPE && vp->v_count > 1) {
+ if (vp->v_pipe == I_PIPE && vp->v_ref_count > 1) {
/* Save the file position in the v-node in case needed later.
* The read and write positions are saved separately.
*/
#include "vnode.h"
#include "param.h"
+FORWARD _PROTOTYPE( int Xlookup, (lookup_req_t *lookup_req,
+ node_details_t *node, char **pathrem) );
/*===========================================================================*
* lookup *
}
if (!start_node) {
printf("VFSlookup: mounted partition couldn't be found\n");
+ printf("VFSlookup: res.inode_nr = %d, res.fs_e = %d\n",
+ res.inode_nr, res.fs_e);
return ENOENT;
}
r = req_lookup(&req, &res);
}
- /* If success, fill in response fields */
- if (OK == r) {
- node->inode_nr = res.inode_nr;
- node->fmode = res.fmode;
- node->fsize = res.fsize;
- node->dev = res.dev;
- node->fs_e = res.fs_e;
+ /* Fill in response fields */
+ node->inode_nr = res.inode_nr;
+ node->fmode = res.fmode;
+ node->fsize = res.fsize;
+ node->dev = res.dev;
+ node->fs_e = res.fs_e;
+ node->uid = res.uid;
+ node->gid = res.gid;
+
+ return r;
+}
+
+
+/*===========================================================================*
+ * Xlookup *
+ *===========================================================================*/
+PRIVATE int Xlookup(lookup_req, node, pathrem)
+lookup_req_t *lookup_req;
+node_details_t *node;
+char **pathrem;
+{
+ struct vmnt *vmp;
+ struct vnode *start_node;
+ struct lookup_res res;
+ int r, symloop = 0;
+ int cum_path_processed = 0;
+
+ /* Make a copy of the request so that the original values will be kept */
+ struct lookup_req req = *lookup_req;
+ char *fullpath = lookup_req->path;
+
+ /* Clear pathrem */
+ *pathrem= NULL;
+
+ /* Empty (start) path? */
+ if (fullpath[0] == '\0') {
+ return ENOENT;
+ }
+
+ /* Set user and group ids according to the system call */
+ req.uid = (call_nr == ACCESS ? fp->fp_realuid : fp->fp_effuid);
+ req.gid = (call_nr == ACCESS ? fp->fp_realgid : fp->fp_effgid);
+
+ /* Set the starting directories inode number and FS endpoint */
+ start_node = (fullpath[0] == '/' ? fp->fp_rd : fp->fp_wd);
+ req.start_dir = start_node->v_inode_nr;
+ req.fs_e = start_node->v_fs_e;
+
+ /* Is the process' root directory on the same partition?,
+ * if so, set the chroot directory too. */
+ if (fp->fp_rd->v_dev == fp->fp_wd->v_dev)
+ req.root_dir = fp->fp_rd->v_inode_nr;
+ else
+ req.root_dir = 0;
+
+ req.symloop = symloop;
+
+ /* Issue the request */
+ r = req_lookup(&req, &res);
+
+ /* While the response is related to mount control set the
+ * new requests respectively */
+ while (r == EENTERMOUNT || r == ELEAVEMOUNT || r == ESYMLINK) {
+
+ /* If a symlink was encountered during the lookup the
+ * new path has been copied back and the number of characters
+ * processed has been started over. */
+ if (r == ESYMLINK || res.symloop > symloop) {
+ /* The link's content is copied back to the user_fullpath
+ * array. Use it as the path argument from now on... */
+ fullpath = user_fullpath;
+ cum_path_processed = res.char_processed;
+ }
+ else {
+ /* Otherwise, cumulate the characters already processsed from
+ * the path */
+ cum_path_processed += res.char_processed;
+ }
+
+ /* Remember the current value of the symloop counter */
+ symloop = res.symloop;
+
+ /* Symlink encountered with absolute path */
+ if (r == ESYMLINK) {
+ start_node = fp->fp_rd;
+ }
+ /* Entering a new partition */
+ else if (r == EENTERMOUNT) {
+ start_node = 0;
+ /* Start node is now the mounted partition's root node */
+ for (vmp = &vmnt[0]; vmp != &vmnt[NR_MNTS]; ++vmp) {
+ if (vmp->m_mounted_on->v_inode_nr == res.inode_nr
+ && vmp->m_mounted_on->v_fs_e == res.fs_e) {
+ start_node = vmp->m_root_node;
+ break;
+ }
+ }
+ if (!start_node) {
+ printf("VFSlookup: mounted partition couldn't be found\n");
+ printf("VFSlookup: res.inode_nr = %d, res.fs_e = %d\n",
+ res.inode_nr, res.fs_e);
+ return ENOENT;
+ }
+
+ }
+ /* Climbing up mount */
+ else {
+ /* Find the vmnt that represents the partition on
+ * which we "climb up". */
+ if ((vmp = find_vmnt(res.fs_e)) == NIL_VMNT) {
+ printf("VFS: couldn't find vmnt during the climbup!\n");
+ return ENOENT;
+ }
+ /* Start node is the vnode on which the partition is
+ * mounted */
+ start_node = vmp->m_mounted_on;
+ }
+ /* Fill in the request fields */
+ req.start_dir = start_node->v_inode_nr;
+ req.fs_e = start_node->v_fs_e;
+
+ /* Is the process' root directory on the same partition?*/
+ if (start_node->v_dev == fp->fp_rd->v_dev)
+ req.root_dir = fp->fp_rd->v_inode_nr;
+ else
+ req.root_dir = 0;
+
+ /* Fill in the current path name */
+ req.path = &fullpath[cum_path_processed];
+ req.symloop = symloop;
+
+ /* Issue the request */
+ r = req_lookup(&req, &res);
}
+
+ if (r == ENOENT)
+ {
+ cum_path_processed += res.char_processed;
+ *pathrem= &fullpath[cum_path_processed];
+ }
+
+ /* Fill in response fields */
+ node->inode_nr = res.inode_nr;
+ node->fmode = res.fmode;
+ node->fsize = res.fsize;
+ node->dev = res.dev;
+ node->fs_e = res.fs_e;
+ node->uid = res.uid;
+ node->gid = res.gid;
return r;
}
+
+/*===========================================================================*
+ * lookup_vp *
+ *===========================================================================*/
+PUBLIC int lookup_vp(lookup_req, vpp)
+lookup_req_t *lookup_req;
+struct vnode **vpp;
+{
+ int r, lookup_res;
+ struct vnode *vp;
+ struct vmnt *vmp;
+ node_req_t node_req;
+ struct node_details res;
+
+ lookup_res = lookup(lookup_req, &res);
+
+ if (res.inode_nr == 0)
+ {
+ printf("lookup_vp: lookup returned no inode\n");
+ printf("lookup_res = %d, last = '%s'\n",
+ lookup_res, lookup_req->lastc);
+ *vpp= NULL;
+ return lookup_res;
+ }
+
+ /* Check whether vnode is already in use or not */
+ if ((vp = find_vnode(res.fs_e, res.inode_nr)) != NIL_VNODE) {
+ vp->v_ref_count++;
+ *vpp= vp;
+ return lookup_res;
+ }
+
+ /* See if free vnode is available */
+ if ((vp = get_free_vnode(__FILE__, __LINE__)) == NIL_VNODE) {
+ printf("VFS lookup_vp: no free vnode available\n");
+ *vpp= NULL;
+ return EINVAL;
+ }
+
+ /* Fill in request message fields.*/
+ node_req.fs_e = res.fs_e;
+ node_req.inode_nr = res.inode_nr;
+
+ /* Issue request */
+ if ((r = req_getnode(&node_req, &res)) != OK)
+ {
+ printf("lookup_vp: req_getnode failed: %d\n", r);
+ *vpp= NULL;
+ return r;
+ }
+
+ /* Fill in the free vnode's fields */
+ vp->v_fs_e = res.fs_e;
+ vp->v_inode_nr = res.inode_nr;
+ vp->v_mode = res.fmode;
+ vp->v_size = res.fsize;
+ vp->v_uid = res.uid;
+ vp->v_gid = res.gid;
+ vp->v_sdev = res.dev;
+
+ if ( (vmp = find_vmnt(vp->v_fs_e)) == NIL_VMNT)
+ panic(__FILE__, "lookup_vp: vmnt not found", NO_NUM);
+
+ vp->v_vmnt = vmp;
+ vp->v_dev = vmp->m_dev;
+ vp->v_fs_count = 1;
+ vp->v_ref_count = 1;
+
+ *vpp= vp;
+ return lookup_res;
+}
+
+/*===========================================================================*
+ * Xlookup_vp *
+ *===========================================================================*/
+PUBLIC int Xlookup_vp(lookup_req, vpp, pathrem)
+lookup_req_t *lookup_req;
+struct vnode **vpp;
+char **pathrem;
+{
+ int r, lookup_res;
+ struct vnode *vp;
+ struct vmnt *vmp;
+ node_req_t node_req;
+ struct node_details res;
+
+ lookup_res = Xlookup(lookup_req, &res, pathrem);
+
+ if (res.inode_nr == 0)
+ {
+ printf("Xlookup_vp: lookup returned no inode\n");
+ printf("lookup_res = %d, last = '%s'\n",
+ lookup_res, lookup_req->lastc);
+ *vpp= NULL;
+ return lookup_res;
+ }
+
+ /* Check whether vnode is already in use or not */
+ if ((vp = find_vnode(res.fs_e, res.inode_nr)) != NIL_VNODE) {
+ vp->v_ref_count++;
+ *vpp= vp;
+ return lookup_res;
+ }
+
+ /* See if free vnode is available */
+ if ((vp = get_free_vnode(__FILE__, __LINE__)) == NIL_VNODE) {
+ printf("VFS Xlookup_vp: no free vnode available\n");
+ *vpp= NULL;
+ return EINVAL;
+ }
+
+ /* Fill in request message fields.*/
+ node_req.fs_e = res.fs_e;
+ node_req.inode_nr = res.inode_nr;
+
+ /* Issue request */
+ if ((r = req_getnode(&node_req, &res)) != OK)
+ {
+ printf("Xlookup_vp: req_getnode failed: %d\n", r);
+ *vpp= NULL;
+ return r;
+ }
+
+ /* Fill in the free vnode's fields */
+ vp->v_fs_e = res.fs_e;
+ vp->v_inode_nr = res.inode_nr;
+ vp->v_mode = res.fmode;
+ vp->v_size = res.fsize;
+ vp->v_uid = res.uid;
+ vp->v_gid = res.gid;
+ vp->v_sdev = res.dev;
+
+ if ( (vmp = find_vmnt(vp->v_fs_e)) == NIL_VMNT)
+ panic(__FILE__, "Xlookup_vp: vmnt not found", NO_NUM);
+
+ vp->v_vmnt = vmp;
+ vp->v_dev = vmp->m_dev;
+ vp->v_fs_count = 1;
+ vp->v_ref_count = 1;
+
+ *vpp= vp;
+ return lookup_res;
+}
+
struct node_details res;
/* See if a free vnode is available */
- if ( (vp = get_free_vnode()) == NIL_VNODE) {
+ if ( (vp = get_free_vnode(__FILE__, __LINE__)) == NIL_VNODE) {
printf("VFS: no vnode available!\n");
return err_code;
}
vp->v_mode = res.fmode;
vp->v_index = res.inode_index;
vp->v_pipe = I_PIPE;
- vp->v_count = 2; /* Double usage */
+ vp->v_fs_count = 2; /* Double usage */
+ vp->v_ref_count = 2; /* Double usage */
vp->v_size = 0;
if ( (vmp = find_vmnt(vp->v_fs_e)) == NIL_VMNT) {
return req_access(&req);
}
+
+/*===========================================================================*
+ * forbidden *
+ *===========================================================================*/
+PUBLIC int forbidden(struct vnode *vp, mode_t access_desired)
+{
+/* Given a pointer to an inode, 'rip', and the access desired, determine
+ * if the access is allowed, and if not why not. The routine looks up the
+ * caller's uid in the 'fproc' table. If access is allowed, OK is returned
+ * if it is forbidden, EACCES is returned.
+ */
+
+ register struct super_block *sp;
+ register mode_t bits, perm_bits;
+ int r, shift, type;
+
+ if (vp->v_uid == (uid_t)-1 || vp->v_gid == (gid_t)-1)
+ {
+ printf("forbidden: bad uid/gid in vnode\n");
+ printf("forbidden: last allocated at %s, %d\n", vp->v_file, vp->v_line);
+ return EACCES;
+ }
+
+ /* Isolate the relevant rwx bits from the mode. */
+ bits = vp->v_mode;
+ if (fp->fp_effuid == SU_UID) {
+ /* Grant read and write permission. Grant search permission for
+ * directories. Grant execute permission (for non-directories) if
+ * and only if one of the 'X' bits is set.
+ */
+ if ( (bits & I_TYPE) == I_DIRECTORY ||
+ bits & ((X_BIT << 6) | (X_BIT << 3) | X_BIT))
+ perm_bits = R_BIT | W_BIT | X_BIT;
+ else
+ perm_bits = R_BIT | W_BIT;
+ } else {
+ if (fp->fp_effuid == vp->v_uid) shift = 6; /* owner */
+ else if (fp->fp_effgid == vp->v_gid ) shift = 3; /* group */
+ else shift = 0; /* other */
+ perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT);
+ }
+
+ /* If access desired is not a subset of what is allowed, it is refused. */
+ r = OK;
+ if ((perm_bits | access_desired) != perm_bits) r = EACCES;
+
+ /* Check to see if someone is trying to write on a file system that is
+ * mounted read-only.
+ */
+ if (r == OK)
+ if (access_desired & W_BIT)
+ r = read_only(vp);
+
+ return(r);
+}
+
+
+/*===========================================================================*
+ * read_only *
+ *===========================================================================*/
+PUBLIC int read_only(vp)
+struct vnode *vp; /* ptr to inode whose file sys is to be cked */
+{
+/* Check to see if the file system on which the inode 'ip' resides is mounted
+ * read only. If so, return EROFS, else return OK.
+ */
+ register struct vmnt *mp;
+
+ mp = vp->v_vmnt;
+ return(mp->m_flags ? EROFS : OK);
+}
+
+
_PROTOTYPE( int do_rename, (void) );
_PROTOTYPE( int do_truncate, (void) );
_PROTOTYPE( int do_ftruncate, (void) );
+_PROTOTYPE( int truncate_vn, (struct vnode *vp, off_t newsize) );
/* lock.c */
_PROTOTYPE( int lock_op, (struct filp *f, int req) );
/* path.c */
_PROTOTYPE( int lookup, (lookup_req_t *request, node_details_t *node) );
+_PROTOTYPE( int lookup_vp, (lookup_req_t *request, struct vnode **vpp) );
+_PROTOTYPE( int Xlookup_vp, (lookup_req_t *request, struct vnode **vpp,
+ char **pathrem) );
/* pipe.c */
_PROTOTYPE( int do_pipe, (void) );
_PROTOTYPE( int do_chmod, (void) );
_PROTOTYPE( int do_chown, (void) );
_PROTOTYPE( int do_umask, (void) );
+_PROTOTYPE( int forbidden, (struct vnode *vp, mode_t access_desired) );
+_PROTOTYPE( int read_only, (struct vnode *vp) );
/* read.c */
_PROTOTYPE( int do_read, (void) );
/* request.c */
_PROTOTYPE( int fs_sendrec, (endpoint_t fs_e, message *reqm) );
_PROTOTYPE( int req_getnode, (node_req_t *req, node_details_t *res) );
-_PROTOTYPE( int req_putnode, (node_req_t *req) );
+_PROTOTYPE( int req_putnode, (int fs_e, ino_t inode_nr, int count) );
_PROTOTYPE( int req_open, (open_req_t *req, node_details_t *res) );
+_PROTOTYPE( int req_create, (int fs_e, ino_t inode_nr, int omode,
+ int uid, int gid, char *path, node_details_t *res) );
_PROTOTYPE( int req_readwrite, (readwrite_req_t *req,
readwrite_res_t *res) );
_PROTOTYPE( int req_pipe, (pipe_req_t *req, node_details_t *res) );
_PROTOTYPE( int req_mknod, (mknod_req_t *req) );
_PROTOTYPE( int req_mkdir, (mkdir_req_t *req) );
_PROTOTYPE( int req_inhibread, (node_req_t *req) );
-_PROTOTYPE( int req_stat, (stat_req_t *req) );
-_PROTOTYPE( int req_fstat, (stat_req_t *req) );
-_PROTOTYPE( int req_fstatfs, (stat_req_t *req) );
+_PROTOTYPE( int req_stat, (int fs_e, ino_t inode_nr, int who_e,
+ char *buf, int pos) );
+_PROTOTYPE( int req_fstatfs, (int fs_e, ino_t inode_nr, int who_e,
+ char *buf) );
_PROTOTYPE( int req_unlink, (unlink_req_t *req) );
_PROTOTYPE( int req_rmdir, (unlink_req_t *req) );
_PROTOTYPE( int req_utime, (utime_req_t *req) );
_PROTOTYPE( int req_stime, (endpoint_t fs_e, time_t boottime) );
_PROTOTYPE( int req_sync, (endpoint_t fs_e) );
-_PROTOTYPE( int req_getdir, (getdir_req_t *req, node_details_t *res) );
_PROTOTYPE( int req_link, (link_req_t *req) );
_PROTOTYPE( int req_slink, (slink_req_t *req) );
_PROTOTYPE( int req_rdlink, (rdlink_req_t *req) );
_PROTOTYPE( struct vmnt *find_vmnt, (int fs_e) );
/* vnode.c */
-_PROTOTYPE( struct vnode *get_free_vnode, (void) );
+_PROTOTYPE( struct vnode *get_free_vnode, (char *file, int line) );
_PROTOTYPE( struct vnode *find_vnode, (int fs_e, int numb) );
_PROTOTYPE( void dup_vnode, (struct vnode *vp) );
_PROTOTYPE( void put_vnode, (struct vnode *vp) );
+_PROTOTYPE( void vnode_clean_refs, (struct vnode *vp) );
_PROTOTYPE( struct vnode *get_vnode, (int fs_e, int inode_nr) );
+_PROTOTYPE( struct vnode *get_vnode_x, (int fs_e, int inode_nr) );
+#if 0
+_PROTOTYPE( void mark_vn, (struct vnode *vp, char *file, int line) );
+_PROTOTYPE( int check_vrefs, (void) );
+#endif
/* write.c */
_PROTOTYPE( int do_write, (void) );
req.user_addr = m_in.buffer;
req.inode_index = vp->v_index;
+ if (vp->v_isfifo)
+ {
+ printf("read_write: %s for FIFO @ %u size %u\n",
+ (rw_flag == READING) ? "read" : "write",
+ ex64lo(position), m_in.nbytes);
+ }
+
/* Issue request */
r = req_readwrite(&req, &res);
#include "fs.h"
#include <string.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
#include <minix/callnr.h>
#include <minix/com.h>
#include <minix/keymap.h>
res->fmode = m.RES_MODE;
res->fsize = m.RES_FILE_SIZE;
res->dev = m.RES_DEV;
+ res->uid = m.RES_UID;
+ res->gid = m.RES_GID;
return OK;
}
/*===========================================================================*
* req_putnode *
*===========================================================================*/
-PUBLIC int req_putnode(req)
-node_req_t *req;
+PUBLIC int req_putnode(fs_e, inode_nr, count)
+int fs_e;
+ino_t inode_nr;
+int count;
{
message m;
/* Fill in request message */
m.m_type = REQ_PUTNODE;
- m.REQ_INODE_NR = req->inode_nr;
+ m.REQ_INODE_NR = inode_nr;
+ m.REQ_COUNT = count;
/* Send/rec request */
- return fs_sendrec(req->fs_e, &m);
+ return fs_sendrec(fs_e, &m);
}
/*===========================================================================*
}
+/*===========================================================================*
+ * req_create *
+ *===========================================================================*/
+int req_create(fs_e, inode_nr, omode, uid, gid, path, res)
+int fs_e;
+ino_t inode_nr;
+int omode;
+uid_t uid;
+gid_t gid;
+char *path;
+node_details_t *res;
+{
+ int r;
+ message m;
+
+ /* Fill in request message */
+ m.m_type = REQ_CREATE;
+ m.REQ_INODE_NR = inode_nr;
+ m.REQ_MODE = omode;
+ m.REQ_UID = uid;
+ m.REQ_GID = gid;
+ m.REQ_PATH = path;
+ m.REQ_PATH_LEN = strlen(path) + 1;
+
+ /* Send/rec request */
+ if ((r = fs_sendrec(fs_e, &m)) != OK) return r;
+
+ /* Fill in response structure */
+ res->fs_e = m.m_source;
+ res->inode_nr = m.RES_INODE_NR;
+ res->fmode = m.RES_MODE;
+ res->fsize = m.RES_FILE_SIZE;
+ res->dev = m.RES_DEV;
+ res->inode_index = m.RES_INODE_INDEX;
+ /* For exec */
+ res->uid = m.RES_UID;
+ res->gid = m.RES_GID;
+ res->ctime = m.RES_CTIME;
+
+ return OK;
+}
+
+
/*===========================================================================*
* req_readwrite *
*===========================================================================*/
/*===========================================================================*
* req_stat *
*===========================================================================*/
-PUBLIC int req_stat(req)
-stat_req_t *req;
+PUBLIC int req_stat(fs_e, inode_nr, who_e, buf, pos)
+int fs_e;
+ino_t inode_nr;
+int who_e;
+char *buf;
+int pos;
{
- message m;
+ cp_grant_id_t gid;
+ int r;
+ message m;
+ struct stat sb;
+
+ if (pos != 0)
+ {
+ gid= cpf_grant_direct(fs_e, (vir_bytes)&sb, sizeof(struct stat),
+ CPF_WRITE);
+ }
+ else
+ {
+ gid= cpf_grant_magic(fs_e, who_e, (vir_bytes)buf, sizeof(struct stat),
+ CPF_WRITE);
+ }
+ if (gid < 0)
+ return gid;
- /* Fill in request message */
- m.m_type = REQ_STAT;
- m.REQ_INODE_NR = req->inode_nr;
- m.REQ_UID = req->uid;
- m.REQ_GID = req->gid;
- m.REQ_WHO_E = req->who_e;
- m.REQ_USER_ADDR = req->buf;
+ /* Fill in request message */
+ m.m_type = REQ_STAT;
+ m.REQ_INODE_NR = inode_nr;
+ m.REQ_GRANT = gid;
- /* Send/rec request */
- return fs_sendrec(req->fs_e, &m);
-}
+ /* Send/rec request */
+ r= fs_sendrec(fs_e, &m);
+ cpf_revoke(gid);
-/*===========================================================================*
- * req_fstat *
- *===========================================================================*/
-PUBLIC int req_fstat(req)
-stat_req_t *req;
-{
- message m;
-
- /* Fill in request message */
- m.m_type = REQ_FSTAT;
- m.REQ_FD_INODE_NR = req->inode_nr;
- m.REQ_FD_WHO_E = req->who_e;
- m.REQ_FD_USER_ADDR = req->buf;
- m.REQ_FD_POS = req->pos;
+ if (r == OK && pos != 0)
+ {
+ sb.st_size -= pos;
+ r= sys_vircopy(SELF, D, (vir_bytes)&sb, who_e, D, (vir_bytes)buf,
+ sizeof(struct stat));
+ }
- /* Send/rec request */
- return fs_sendrec(req->fs_e, &m);
+ return r;
}
/*===========================================================================*
* req_fstatfs *
*===========================================================================*/
-PUBLIC int req_fstatfs(req)
-stat_req_t *req;
+PUBLIC int req_fstatfs(fs_e, inode_nr, who_e, buf)
+int fs_e;
+ino_t inode_nr;
+int who_e;
+char *buf;
{
- message m;
+ int r;
+ cp_grant_id_t gid;
+ message m;
- /* Fill in request message */
- m.m_type = REQ_FSTATFS;
- m.REQ_FD_INODE_NR = req->inode_nr;
- m.REQ_FD_WHO_E = req->who_e;
- m.REQ_FD_USER_ADDR = req->buf;
+ gid= cpf_grant_magic(fs_e, who_e, (vir_bytes)buf, sizeof(struct statfs),
+ CPF_WRITE);
+ if (gid < 0)
+ return gid;
- /* Send/rec request */
- return fs_sendrec(req->fs_e, &m);
+ /* Fill in request message */
+ m.m_type = REQ_FSTATFS;
+ m.REQ_INODE_NR = inode_nr;
+ m.REQ_GRANT = gid;
+
+ /* Send/rec request */
+ r= fs_sendrec(fs_e, &m);
+
+ cpf_revoke(gid);
+
+ return r;
}
}
-/*===========================================================================*
- * req_getdir *
- *===========================================================================*/
-PUBLIC int req_getdir(req, res)
-getdir_req_t *req;
-node_details_t *res;
-{
- int r;
- message m;
-
- /* Fill in request message */
- m.m_type = REQ_GETDIR;
- m.REQ_INODE_NR = req->inode_nr;
- m.REQ_UID = req->uid;
- m.REQ_GID = req->gid;
-
- /* Send/rec request */
- if ((r = fs_sendrec(req->fs_e, &m)) != OK) return r;
-
- /* Fill in response structure */
- res->fs_e = m.m_source;
- res->inode_nr = m.RES_INODE_NR;
- res->fmode = m.RES_MODE;
- res->fsize = m.RES_FILE_SIZE;
-
- return OK;
-}
-
-
/*===========================================================================*
* req_link *
*===========================================================================*/
res->fs_e = m.m_source;
switch (r) {
case OK:
+ default:
res->inode_nr = m.RES_INODE_NR;
res->fmode = m.RES_MODE;
res->fsize = m.RES_FILE_SIZE;
res->dev = m.RES_DEV;
+ res->uid= m.RES_UID;
+ res->gid= m.RES_GID;
+ res->char_processed = m.RES_OFFSET; /* For ENOENT */
break;
case EENTERMOUNT:
res->inode_nr = m.RES_INODE_NR;
} mkdir_req_t;
-/* Structure for REQ_STAT, REQ_FSTAT, REQ_FSTATFS requests */
-typedef struct stat_req {
- int fs_e;
- ino_t inode_nr;
- uid_t uid;
- gid_t gid;
- int who_e;
- char *buf;
- int pos;
-} stat_req_t;
-
/* Structure for REQ_UNLINK request */
typedef struct unlink_req {
int fs_e;
} utime_req_t;
-/* Structure for REQ_GETDIR request */
-typedef struct getdir_req {
- endpoint_t fs_e;
- ino_t inode_nr;
- uid_t uid;
- gid_t gid;
-} getdir_req_t;
-
-
/* Structure for REQ_LINK request */
typedef struct link_req {
endpoint_t fs_e;
ino_t inode_nr;
mode_t fmode;
off_t fsize;
+ uid_t uid;
+ gid_t gid;
/* For char/block special files */
dev_t dev;
{
/* Change directory on already-opened fd. */
struct filp *rfilp;
- struct getdir_req req;
- struct node_details res;
int r;
/* Is the file descriptor valid? */
if ((rfilp->filp_vno->v_mode & I_TYPE) != I_DIRECTORY)
return ENOTDIR;
- /* Fill in request message fields.*/
- req.fs_e = rfilp->filp_vno->v_fs_e;
- req.inode_nr = rfilp->filp_vno->v_inode_nr;
- req.uid = fp->fp_effuid;
- req.gid = fp->fp_effgid;
-
/* Issue request and handle error */
- if ((r = req_getdir(&req, &res)) != OK) return r;
+ r = forbidden(rfilp->filp_vno, X_BIT);
+ if (r != OK) return r;
- /* GETDIR increased the counter in the FS proc */
- rfilp->filp_vno->v_count++;
+ rfilp->filp_vno->v_ref_count++; /* change_into expects a reference */
return change_into(&fp->fp_wd, rfilp->filp_vno);
}
int len; /* length of the directory name string */
{
/* Do the actual work for chdir() and chroot(). */
- struct vnode *vp, *vp2;
- struct vmnt *vmp;
- struct getdir_req req;
- struct node_details res;
+ struct vnode *vp;
struct lookup_req lookup_req;
int r;
if (fetch_name(name_ptr, len, M3) != OK) return(err_code);
- /* See if free vnode is available */
- if ((vp = get_free_vnode()) == NIL_VNODE) {
- printf("VFSchange: no free vnode available\n");
- return EINVAL;
- }
-
/* Fill in lookup request fields */
lookup_req.path = user_fullpath;
lookup_req.lastc = NULL;
lookup_req.flags = EAT_PATH;
/* Request lookup */
- if ((r = lookup(&lookup_req, &res)) != OK) return r;
+ if ((r = lookup_vp(&lookup_req, &vp)) != OK) return r;
/* Is it a dir? */
- if ((res.fmode & I_TYPE) != I_DIRECTORY)
+ if ((vp->v_mode & I_TYPE) != I_DIRECTORY)
+ {
+ put_vnode(vp);
return ENOTDIR;
-
- /* Fill in request message fields.*/
- req.fs_e = res.fs_e;
- req.inode_nr = res.inode_nr;
- req.uid = fp->fp_effuid;
- req.gid = fp->fp_effgid;
-
- /* Issue request */
- if ((r = req_getdir(&req, &res)) != OK) return r;
-
- /* Check whether vnode is already in use or not */
- if ((vp2 = find_vnode(res.fs_e, res.inode_nr))
- != NIL_VNODE) {
- vp2->v_count++;
- vp = vp2;
- }
- else {
- /* Fill in the free vnode's fields */
- vp->v_fs_e = res.fs_e;
- vp->v_inode_nr = res.inode_nr;
- vp->v_mode = res.fmode;
- vp->v_size = res.fsize;
-
- if ( (vmp = find_vmnt(vp->v_fs_e)) == NIL_VMNT)
- printf("VFSchange: vmnt not found");
-
- vp->v_vmnt = vmp;
- vp->v_dev = vmp->m_dev;
- vp->v_count = 1;
}
-
+
return change_into(iip, vp);
}
PUBLIC int do_stat()
{
/* Perform the stat(name, buf) system call. */
- struct stat_req req;
struct node_details res;
struct lookup_req lookup_req;
int r;
/* Request lookup */
if ((r = lookup(&lookup_req, &res)) != OK) return r;
- /* Fill in request message fields.*/
- req.fs_e = res.fs_e;
- req.who_e = who_e;
- req.buf = m_in.name2;
- req.inode_nr = res.inode_nr;
- req.uid = fp->fp_effuid;
- req.gid = fp->fp_effgid;
-
/* Issue request */
- return req_stat(&req);
+ return req_stat(res.fs_e, res.inode_nr, who_e, m_in.name2, 0);
}
/* Perform the fstat(fd, buf) system call. */
register struct filp *rfilp;
int pipe_pos = 0;
- struct stat_req req;
/* Is the file descriptor valid? */
if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) {
}
/* If we read from a pipe, send position too */
+ pipe_pos= 0;
if (rfilp->filp_vno->v_pipe == I_PIPE) {
if (rfilp->filp_mode & R_BIT)
if (ex64hi(rfilp->filp_pos) != 0)
pipe_pos = ex64lo(rfilp->filp_pos);
}
- /* Fill in request message */
- req.fs_e = rfilp->filp_vno->v_fs_e;
- req.inode_nr = rfilp->filp_vno->v_inode_nr;
- req.pos = pipe_pos;
- req.who_e = who_e;
- req.buf = m_in.buffer;
-
/* Issue request */
- return req_fstat(&req);
+ return req_stat(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr,
+ who_e, m_in.buffer, pipe_pos);
}
{
/* Perform the fstatfs(fd, buf) system call. */
register struct filp *rfilp;
- struct stat_req req;
/* Is the file descriptor valid? */
if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
- /* Send FS request */
- req.fs_e = rfilp->filp_vno->v_fs_e;
- req.inode_nr = rfilp->filp_vno->v_inode_nr;
- req.who_e = who_e;
- req.buf = m_in.buffer;
-
/* Issue request */
- return req_fstatfs(&req);
+ return req_fstatfs(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr,
+ who_e, m_in.buffer);
}
PUBLIC int do_lstat()
{
/* Perform the lstat(name, buf) system call. */
- struct stat_req req;
struct node_details res;
struct lookup_req lookup_req;
int r;
/* Request lookup */
if ((r = lookup(&lookup_req, &res)) != OK) return r;
- /* Fill in request message fields.*/
- req.fs_e = res.fs_e;
- req.who_e = who_e;
- req.buf = m_in.name2;
- req.inode_nr = res.inode_nr;
- req.uid = fp->fp_effuid;
- req.gid = fp->fp_effgid;
-
/* Issue request */
- return req_stat(&req);
+ return req_stat(res.fs_e, res.inode_nr, who_e, m_in.name2, 0);
}
#include "vnode.h"
#include "vmnt.h"
+#include "fproc.h"
+#include "file.h"
+
#include <minix/vfsif.h>
/*===========================================================================*
/* Request & response structures */
struct node_req req;
struct node_details res;
+
+ /* XXX remove this when debugging is complete */
+ if (find_vnode(fs_e, inode_nr) != NULL)
+ panic(__FILE__, "get_vnode: vnode already present", NO_NUM);
/* Check whether a free vnode is avaliable */
- if ((vp = get_free_vnode()) == NIL_VNODE) {
+ if ((vp = get_free_vnode(__FILE__, __LINE__)) == NIL_VNODE) {
printf("VFSget_vnode: no vnode available\n");
return NIL_VNODE;
}
vp->v_vmnt = vmp;
vp->v_dev = vmp->m_dev;
- vp->v_count = 1;
+ vp->v_fs_count = 1;
+ vp->v_ref_count = 1;
return vp;
}
+/*===========================================================================*
+ * get_vnode *
+ *===========================================================================*/
+PUBLIC struct vnode *get_vnode_x(int fs_e, int inode_nr)
+{
+/* get_vnode() is called to get the details of the specified inode.
+ * Note that inode's usage counter in the FS is supposed to be incremented.
+ */
+ struct vnode *vp, *vp2;
+ struct vmnt *vmp;
+
+ /* Request & response structures */
+ struct node_req req;
+ struct node_details res;
+
+ vp= find_vnode(fs_e, inode_nr);
+ if (vp)
+ {
+ vp->v_ref_count++;
+ return vp;
+ }
+
+ return get_vnode(fs_e, inode_nr);
+}
+
+
/*===========================================================================*
* get_free_vnode *
*===========================================================================*/
-PUBLIC struct vnode *get_free_vnode()
+PUBLIC struct vnode *get_free_vnode(file, line)
+char *file;
+int line;
{
/* Find a free vnode slot in the vnode table */
struct vnode *vp;
for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp)
- if (vp->v_count == 0) return vp;
+ if (vp->v_ref_count == 0)
+ {
+ vp->v_pipe= NO_PIPE;
+ vp->v_uid= -1;
+ vp->v_gid= -1;
+ vp->v_sdev= -1;
+ vp->v_file= file;
+ vp->v_line= line;
+ return vp;
+ }
+
err_code = ENFILE;
return NIL_VNODE;
struct vnode *vp;
for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp)
- if (vp->v_count > 0 && vp->v_inode_nr == numb
+ if (vp->v_ref_count > 0 && vp->v_inode_nr == numb
&& vp->v_fs_e == fs_e) return vp;
return NIL_VNODE;
/* dup_vnode() is called to increment the vnode and therefore the
* referred inode's counter.
*/
- struct node_req req;
- struct node_details res;
-
if (vp == NIL_VNODE) {
printf("VFSdup_vnode NIL_VNODE\n");
return;
}
- /* Fill req struct */
- req.inode_nr = vp->v_inode_nr;
- req.fs_e = vp->v_fs_e;
-
- /* Send request to FS */
- if (req_getnode(&req, &res) != OK)
- printf("VFSdup_vnode Warning: inode doesn't exist\n");
- else
- vp->v_count++;
+ vp->v_ref_count++;
}
/* Decrease vnode's usage counter and decrease inode's usage counter in the
* corresponding FS process.
*/
- struct node_req req;
-
if (vp == NIL_VNODE) {
/*printf("VFSput_vnode NIL_VNODE\n");*/
return;
}
- /* Fill in request fields */
- req.fs_e = vp->v_fs_e;
- req.inode_nr = vp->v_inode_nr;
+ if (vp < &vnode[0] || vp >= &vnode[NR_VNODES])
+ {
+ printf("put_vnode: &vnode[0] = %p, &vnode[NR_VNODES] = %p, vp = %p\n",
+ &vnode[0], &vnode[NR_VNODES], vp);
+ panic(__FILE__, "put_vnode: bad vnode pointer", NO_NUM);
+ }
- /* Send request */
- if (req_putnode(&req) == OK) {
- /* Decrease counter */
- if (--vp->v_count == 0) {
- vp->v_pipe = NO_PIPE;
- vp->v_sdev = NO_DEV;
- vp->v_index = 0;
- }
+ if (vp->v_ref_count > 1)
+ {
+ /* Decrease counter */
+ vp->v_ref_count--;
+ if (vp->v_fs_count > 256)
+ vnode_clean_refs(vp);
+ return;
+ }
+
+ if (vp->v_ref_count <= 0)
+ {
+ printf("put_vnode: bad v_ref_count %d\n", vp->v_ref_count);
+ panic(__FILE__, "put_vnode failed", NO_NUM);
+ }
+ if (vp->v_fs_count <= 0)
+ {
+ printf("put_vnode: bad v_fs_count %d\n", vp->v_fs_count);
+ panic(__FILE__, "put_vnode failed", NO_NUM);
}
- else
+
+ /* Send request */
+ if (req_putnode(vp->v_fs_e, vp->v_inode_nr, vp->v_fs_count) != OK)
printf("VFSput_vnode Warning: inode doesn't exist\n");
+
+ vp->v_fs_count= 0;
+ vp->v_ref_count= 0;
+ vp->v_pipe = NO_PIPE;
+ vp->v_sdev = NO_DEV;
+ vp->v_index = 0;
}
+/*===========================================================================*
+ * vnode_clean_refs *
+ *===========================================================================*/
+PUBLIC void vnode_clean_refs(struct vnode *vp)
+{
+/* Tell the underlying FS to drop all reference but one. */
+ if (vp == NIL_VNODE) {
+ return;
+ }
+
+ if (vp->v_fs_count <= 1)
+ return; /* Nothing to do */
+ printf("vnode_clean_refs: dropping some references at FS\n");
+ if (req_putnode(vp->v_fs_e, vp->v_inode_nr, vp->v_fs_count-1) != OK)
+ printf("vnode_clean_refs: req_putnode failed\n");
+ vp->v_fs_count= 1;
+}
+
+
+#if 0
+/*===========================================================================*
+ * mark_vn *
+ *===========================================================================*/
+PUBLIC void mark_vn(vp, file, line)
+struct vnode *vp;
+char *file;
+int line;
+{
+ if (!vp)
+ return;
+ vp->v_file= file;
+ vp->v_line= line;
+}
+
+
+/*===========================================================================*
+ * check_vrefs *
+ *===========================================================================*/
+PUBLIC int check_vrefs()
+{
+ int i, bad;
+ int ispipe_flag, ispipe_mode;
+ struct vnode *vp;
+ struct vmnt *vmp;
+ struct fproc *rfp;
+ struct filp *f;
+
+ /* Clear v_ref_check */
+ for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp)
+ vp->v_ref_check= 0;
+
+ /* Count reference for processes */
+ for (rfp=&fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
+ if (rfp->fp_pid == PID_FREE)
+ continue;
+ vp= rfp->fp_rd;
+ if (vp < &vnode[0] || vp >= &vnode[NR_VNODES])
+ panic(__FILE__, "check_vrefs: bad vnode", NO_NUM);
+ vp->v_ref_check++;
+
+ vp= rfp->fp_wd;
+ if (vp < &vnode[0] || vp >= &vnode[NR_VNODES])
+ panic(__FILE__, "check_vrefs: bad vnode", NO_NUM);
+ vp->v_ref_check++;
+
+ }
+
+ /* Count references from filedescriptors */
+ for (f = &filp[0]; f < &filp[NR_FILPS]; f++)
+ {
+ if (f->filp_count == 0)
+ continue;
+ vp= f->filp_vno;
+ if (vp < &vnode[0] || vp >= &vnode[NR_VNODES])
+ panic(__FILE__, "check_vrefs: bad vnode", NO_NUM);
+ vp->v_ref_check++;
+ }
+
+ /* Count references to mount points */
+ for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp)
+ {
+ if (vmp->m_dev == NO_DEV)
+ continue;
+ vp= vmp->m_mounted_on;
+ if (vp < &vnode[0] || vp >= &vnode[NR_VNODES])
+ panic(__FILE__, "check_vrefs: bad vnode", NO_NUM);
+ vp->v_ref_check++;
+
+ vp= vmp->m_root_node;
+ if (vp < &vnode[0] || vp >= &vnode[NR_VNODES])
+ panic(__FILE__, "check_vrefs: bad vnode", NO_NUM);
+ vp->v_ref_check++;
+ }
+
+ /* Check references */
+ bad= 0;
+ for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp)
+ {
+ if (vp->v_ref_count != vp->v_ref_check)
+ {
+ printf(
+"Bad reference count for inode %d on device 0x%x: found %d, listed %d\n",
+ vp->v_inode_nr, vp->v_dev, vp->v_ref_check,
+ vp->v_ref_count);
+ printf("last marked at %s, %d\n",
+ vp->v_file, vp->v_line);
+ bad= 1;
+ }
+
+ /* Also check v_pipe */
+ if (vp->v_ref_count != 0)
+ {
+ ispipe_flag= (vp->v_pipe == I_PIPE);
+ ispipe_mode= ((vp->v_mode & I_TYPE) == I_NAMED_PIPE);
+ if (ispipe_flag != ispipe_mode)
+ {
+ printf(
+"Bad v_pipe for inode %d on device 0x%x: found %d, mode 0%o\n",
+ vp->v_inode_nr, vp->v_dev, vp->v_pipe,
+ vp->v_mode);
+ printf("last marked at %s, %d\n",
+ vp->v_file, vp->v_line);
+ bad= 1;
+ }
+ }
+ }
+ return !bad;
+}
+#endif
endpoint_t v_fs_e; /* FS process' endpoint number */
ino_t v_inode_nr; /* inode number on its (minor) device */
mode_t v_mode; /* file type, protection, etc. */
+ uid_t v_uid;
+ gid_t v_gid;
off_t v_size; /* current file size in bytes */
- int v_count; /* # times vnode used; 0 means slot is free */
+ int v_ref_count; /* # times vnode used; 0 means slot is free */
+ int v_fs_count; /* # reference at the underlying FS */
+ int v_ref_check; /* for consistency checks */
char v_pipe; /* set to I_PIPE if pipe */
off_t v_pipe_rd_pos;
off_t v_pipe_wr_pos;
int v_blocksize; /* block size of the filesys */
unsigned short v_index; /* inode's index in the FS inode table */
struct vmnt *v_vmnt; /* vmnt object of the partition */
+
+ /* For debugging */
+ char *v_file;
+ int v_line;
+ int v_isfifo;
} vnode[NR_VNODES];
#define NIL_VNODE (struct vnode *) 0 /* indicates absence of vnode slot */