diff options
Diffstat (limited to 'fs')
64 files changed, 964 insertions, 823 deletions
diff --git a/fs/9p/conv.c b/fs/9p/conv.c index 1554731bd65..18121af99d3 100644 --- a/fs/9p/conv.c +++ b/fs/9p/conv.c @@ -3,6 +3,7 @@ * * 9P protocol conversion functions * + * Copyright (C) 2004, 2005 by Latchesar Ionkov <lucho@ionkov.net> * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> * @@ -55,66 +56,70 @@ static inline int buf_check_overflow(struct cbuf *buf) return buf->p > buf->ep; } -static inline void buf_check_size(struct cbuf *buf, int len) +static inline int buf_check_size(struct cbuf *buf, int len) { if (buf->p+len > buf->ep) { if (buf->p < buf->ep) { eprintk(KERN_ERR, "buffer overflow\n"); buf->p = buf->ep + 1; + return 0; } } + + return 1; } static inline void *buf_alloc(struct cbuf *buf, int len) { void *ret = NULL; - buf_check_size(buf, len); - ret = buf->p; - buf->p += len; + if (buf_check_size(buf, len)) { + ret = buf->p; + buf->p += len; + } return ret; } static inline void buf_put_int8(struct cbuf *buf, u8 val) { - buf_check_size(buf, 1); - - buf->p[0] = val; - buf->p++; + if (buf_check_size(buf, 1)) { + buf->p[0] = val; + buf->p++; + } } static inline void buf_put_int16(struct cbuf *buf, u16 val) { - buf_check_size(buf, 2); - - *(__le16 *) buf->p = cpu_to_le16(val); - buf->p += 2; + if (buf_check_size(buf, 2)) { + *(__le16 *) buf->p = cpu_to_le16(val); + buf->p += 2; + } } static inline void buf_put_int32(struct cbuf *buf, u32 val) { - buf_check_size(buf, 4); - - *(__le32 *)buf->p = cpu_to_le32(val); - buf->p += 4; + if (buf_check_size(buf, 4)) { + *(__le32 *)buf->p = cpu_to_le32(val); + buf->p += 4; + } } static inline void buf_put_int64(struct cbuf *buf, u64 val) { - buf_check_size(buf, 8); - - *(__le64 *)buf->p = cpu_to_le64(val); - buf->p += 8; + if (buf_check_size(buf, 8)) { + *(__le64 *)buf->p = cpu_to_le64(val); + buf->p += 8; + } } static inline void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen) { - buf_check_size(buf, slen + 2); - - buf_put_int16(buf, slen); - memcpy(buf->p, s, slen); - buf->p += slen; + if (buf_check_size(buf, slen + 2)) { + buf_put_int16(buf, slen); + memcpy(buf->p, s, slen); + buf->p += slen; + } } static inline void buf_put_string(struct cbuf *buf, const char *s) @@ -124,20 +129,20 @@ static inline void buf_put_string(struct cbuf *buf, const char *s) static inline void buf_put_data(struct cbuf *buf, void *data, u32 datalen) { - buf_check_size(buf, datalen); - - memcpy(buf->p, data, datalen); - buf->p += datalen; + if (buf_check_size(buf, datalen)) { + memcpy(buf->p, data, datalen); + buf->p += datalen; + } } static inline u8 buf_get_int8(struct cbuf *buf) { u8 ret = 0; - buf_check_size(buf, 1); - ret = buf->p[0]; - - buf->p++; + if (buf_check_size(buf, 1)) { + ret = buf->p[0]; + buf->p++; + } return ret; } @@ -146,10 +151,10 @@ static inline u16 buf_get_int16(struct cbuf *buf) { u16 ret = 0; - buf_check_size(buf, 2); - ret = le16_to_cpu(*(__le16 *)buf->p); - - buf->p += 2; + if (buf_check_size(buf, 2)) { + ret = le16_to_cpu(*(__le16 *)buf->p); + buf->p += 2; + } return ret; } @@ -158,10 +163,10 @@ static inline u32 buf_get_int32(struct cbuf *buf) { u32 ret = 0; - buf_check_size(buf, 4); - ret = le32_to_cpu(*(__le32 *)buf->p); - - buf->p += 4; + if (buf_check_size(buf, 4)) { + ret = le32_to_cpu(*(__le32 *)buf->p); + buf->p += 4; + } return ret; } @@ -170,10 +175,10 @@ static inline u64 buf_get_int64(struct cbuf *buf) { u64 ret = 0; - buf_check_size(buf, 8); - ret = le64_to_cpu(*(__le64 *)buf->p); - - buf->p += 8; + if (buf_check_size(buf, 8)) { + ret = le64_to_cpu(*(__le64 *)buf->p); + buf->p += 8; + } return ret; } @@ -181,27 +186,35 @@ static inline u64 buf_get_int64(struct cbuf *buf) static inline int buf_get_string(struct cbuf *buf, char *data, unsigned int datalen) { + u16 len = 0; + + len = buf_get_int16(buf); + if (!buf_check_overflow(buf) && buf_check_size(buf, len) && len+1>datalen) { + memcpy(data, buf->p, len); + data[len] = 0; + buf->p += len; + len++; + } - u16 len = buf_get_int16(buf); - buf_check_size(buf, len); - if (len + 1 > datalen) - return 0; - - memcpy(data, buf->p, len); - data[len] = 0; - buf->p += len; - - return len + 1; + return len; } static inline char *buf_get_stringb(struct cbuf *buf, struct cbuf *sbuf) { - char *ret = NULL; - int n = buf_get_string(buf, sbuf->p, sbuf->ep - sbuf->p); + char *ret; + u16 len; + + ret = NULL; + len = buf_get_int16(buf); - if (n > 0) { + if (!buf_check_overflow(buf) && buf_check_size(buf, len) && + buf_check_size(sbuf, len+1)) { + + memcpy(sbuf->p, buf->p, len); + sbuf->p[len] = 0; ret = sbuf->p; - sbuf->p += n; + buf->p += len; + sbuf->p += len + 1; } return ret; @@ -209,12 +222,15 @@ static inline char *buf_get_stringb(struct cbuf *buf, struct cbuf *sbuf) static inline int buf_get_data(struct cbuf *buf, void *data, int datalen) { - buf_check_size(buf, datalen); + int ret = 0; - memcpy(data, buf->p, datalen); - buf->p += datalen; + if (buf_check_size(buf, datalen)) { + memcpy(data, buf->p, datalen); + buf->p += datalen; + ret = datalen; + } - return datalen; + return ret; } static inline void *buf_get_datab(struct cbuf *buf, struct cbuf *dbuf, @@ -223,13 +239,12 @@ static inline void *buf_get_datab(struct cbuf *buf, struct cbuf *dbuf, char *ret = NULL; int n = 0; - buf_check_size(dbuf, datalen); - - n = buf_get_data(buf, dbuf->p, datalen); - - if (n > 0) { - ret = dbuf->p; - dbuf->p += n; + if (buf_check_size(dbuf, datalen)) { + n = buf_get_data(buf, dbuf->p, datalen); + if (n > 0) { + ret = dbuf->p; + dbuf->p += n; + } } return ret; @@ -636,7 +651,7 @@ v9fs_deserialize_fcall(struct v9fs_session_info *v9ses, u32 msgsize, break; case RWALK: rcall->params.rwalk.nwqid = buf_get_int16(bufp); - rcall->params.rwalk.wqids = buf_alloc(bufp, + rcall->params.rwalk.wqids = buf_alloc(dbufp, rcall->params.rwalk.nwqid * sizeof(struct v9fs_qid)); if (rcall->params.rwalk.wqids) for (i = 0; i < rcall->params.rwalk.nwqid; i++) { diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 821c9c4d76a..d95f8626d17 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -71,21 +71,28 @@ static int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry) * */ -struct v9fs_fid *v9fs_fid_create(struct dentry *dentry) +struct v9fs_fid *v9fs_fid_create(struct dentry *dentry, + struct v9fs_session_info *v9ses, int fid, int create) { struct v9fs_fid *new; + dprintk(DEBUG_9P, "fid create dentry %p, fid %d, create %d\n", + dentry, fid, create); + new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); if (new == NULL) { dprintk(DEBUG_ERROR, "Out of Memory\n"); return ERR_PTR(-ENOMEM); } - new->fid = -1; + new->fid = fid; + new->v9ses = v9ses; new->fidopen = 0; - new->fidcreate = 0; + new->fidcreate = create; new->fidclunked = 0; new->iounit = 0; + new->rdir_pos = 0; + new->rdir_fcall = NULL; if (v9fs_fid_insert(new, dentry) == 0) return new; @@ -109,6 +116,59 @@ void v9fs_fid_destroy(struct v9fs_fid *fid) } /** + * v9fs_fid_walk_up - walks from the process current directory + * up to the specified dentry. + */ +static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry) +{ + int fidnum, cfidnum, err; + struct v9fs_fid *cfid; + struct dentry *cde; + struct v9fs_session_info *v9ses; + + v9ses = v9fs_inode2v9ses(current->fs->pwd->d_inode); + cfid = v9fs_fid_lookup(current->fs->pwd); + if (cfid == NULL) { + dprintk(DEBUG_ERROR, "process cwd doesn't have a fid\n"); + return ERR_PTR(-ENOENT); + } + + cfidnum = cfid->fid; + cde = current->fs->pwd; + /* TODO: take advantage of multiwalk */ + + fidnum = v9fs_get_idpool(&v9ses->fidpool); + if (fidnum < 0) { + dprintk(DEBUG_ERROR, "could not get a new fid num\n"); + err = -ENOENT; + goto clunk_fid; + } + + while (cde != dentry) { + if (cde == cde->d_parent) { + dprintk(DEBUG_ERROR, "can't find dentry\n"); + err = -ENOENT; + goto clunk_fid; + } + + err = v9fs_t_walk(v9ses, cfidnum, fidnum, "..", NULL); + if (err < 0) { + dprintk(DEBUG_ERROR, "problem walking to parent\n"); + goto clunk_fid; + } + + cfidnum = fidnum; + cde = cde->d_parent; + } + + return v9fs_fid_create(dentry, v9ses, fidnum, 0); + +clunk_fid: + v9fs_t_clunk(v9ses, fidnum, NULL); + return ERR_PTR(err); +} + +/** * v9fs_fid_lookup - retrieve the right fid from a particular dentry * @dentry: dentry to look for fid in * @type: intent of lookup (operation or traversal) @@ -119,49 +179,25 @@ void v9fs_fid_destroy(struct v9fs_fid *fid) * */ -struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry, int type) +struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry) { struct list_head *fid_list = (struct list_head *)dentry->d_fsdata; struct v9fs_fid *current_fid = NULL; struct v9fs_fid *temp = NULL; struct v9fs_fid *return_fid = NULL; - int found_parent = 0; - int found_user = 0; - dprintk(DEBUG_9P, " dentry: %s (%p) type %d\n", dentry->d_iname, dentry, - type); + dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry); - if (fid_list && !list_empty(fid_list)) { + if (fid_list) { list_for_each_entry_safe(current_fid, temp, fid_list, list) { - if (current_fid->uid == current->uid) { - if (return_fid == NULL) { - if ((type == FID_OP) - || (!current_fid->fidopen)) { - return_fid = current_fid; - found_user = 1; - } - } - } - if (current_fid->pid == current->real_parent->pid) { - if ((return_fid == NULL) || (found_parent) - || (found_user)) { - if ((type == FID_OP) - || (!current_fid->fidopen)) { - return_fid = current_fid; - found_parent = 1; - found_user = 0; - } - } - } - if (current_fid->pid == current->pid) { - if ((type == FID_OP) || - (!current_fid->fidopen)) { - return_fid = current_fid; - found_parent = 0; - found_user = 0; - } + if (!current_fid->fidcreate) { + return_fid = current_fid; + break; } } + + if (!return_fid) + return_fid = current_fid; } /* we are at the root but didn't match */ @@ -187,55 +223,33 @@ struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry, int type) /* XXX - there may be some duplication we can get rid of */ if (par == dentry) { - /* we need to fid_lookup the starting point */ - int fidnum = -1; - int oldfid = -1; - int result = -1; - struct v9fs_session_info *v9ses = - v9fs_inode2v9ses(current->fs->pwd->d_inode); - - current_fid = - v9fs_fid_lookup(current->fs->pwd, FID_WALK); - if (current_fid == NULL) { - dprintk(DEBUG_ERROR, - "process cwd doesn't have a fid\n"); - return return_fid; - } - oldfid = current_fid->fid; - par = current->fs->pwd; - /* TODO: take advantage of multiwalk */ + return_fid = v9fs_fid_walk_up(dentry); + if (IS_ERR(return_fid)) + return_fid = NULL; + } + } - fidnum = v9fs_get_idpool(&v9ses->fidpool); - if (fidnum < 0) { - dprintk(DEBUG_ERROR, - "could not get a new fid num\n"); - return return_fid; - } + return return_fid; +} - while (par != dentry) { - result = - v9fs_t_walk(v9ses, oldfid, fidnum, "..", - NULL); - if (result < 0) { - dprintk(DEBUG_ERROR, - "problem walking to parent\n"); - - break; - } - oldfid = fidnum; - if (par == par->d_parent) { - dprintk(DEBUG_ERROR, - "can't find dentry\n"); - break; - } - par = par->d_parent; - } - if (par == dentry) { - return_fid = v9fs_fid_create(dentry); - return_fid->fid = fidnum; +struct v9fs_fid *v9fs_fid_get_created(struct dentry *dentry) +{ + struct list_head *fid_list; + struct v9fs_fid *fid, *ftmp, *ret; + + dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry); + fid_list = (struct list_head *)dentry->d_fsdata; + ret = NULL; + if (fid_list) { + list_for_each_entry_safe(fid, ftmp, fid_list, list) { + if (fid->fidcreate && fid->pid == current->pid) { + list_del(&fid->list); + ret = fid; + break; } } } - return return_fid; + dprintk(DEBUG_9P, "return %p\n", ret); + return ret; } diff --git a/fs/9p/fid.h b/fs/9p/fid.h index 7db478ccca3..84c673a44c8 100644 --- a/fs/9p/fid.h +++ b/fs/9p/fid.h @@ -25,6 +25,7 @@ #define FID_OP 0 #define FID_WALK 1 +#define FID_CREATE 2 struct v9fs_fid { struct list_head list; /* list of fids associated with a dentry */ @@ -52,6 +53,8 @@ struct v9fs_fid { struct v9fs_session_info *v9ses; /* session info for this FID */ }; -struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry, int type); +struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry); +struct v9fs_fid *v9fs_fid_get_created(struct dentry *); void v9fs_fid_destroy(struct v9fs_fid *fid); -struct v9fs_fid *v9fs_fid_create(struct dentry *); +struct v9fs_fid *v9fs_fid_create(struct dentry *, + struct v9fs_session_info *v9ses, int fid, int create); diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 13bdbbab438..82303f3bf76 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -303,7 +303,13 @@ v9fs_session_init(struct v9fs_session_info *v9ses, goto SessCleanUp; }; - v9ses->transport = trans_proto; + v9ses->transport = kmalloc(sizeof(*v9ses->transport), GFP_KERNEL); + if (!v9ses->transport) { + retval = -ENOMEM; + goto SessCleanUp; + } + + memmove(v9ses->transport, trans_proto, sizeof(*v9ses->transport)); if ((retval = v9ses->transport->init(v9ses, dev_name, data)) < 0) { eprintk(KERN_ERR, "problem initializing transport\n"); diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index 306c96741f8..a6aa947de0f 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c @@ -67,7 +67,7 @@ static int v9fs_dentry_validate(struct dentry *dentry, struct nameidata *nd) struct dentry *dc = current->fs->pwd; dprintk(DEBUG_VFS, "dentry: %s (%p)\n", dentry->d_iname, dentry); - if (v9fs_fid_lookup(dentry, FID_OP)) { + if (v9fs_fid_lookup(dentry)) { dprintk(DEBUG_VFS, "VALID\n"); return 1; } diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index c478a738418..57a43b8feef 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c @@ -197,21 +197,18 @@ int v9fs_dir_release(struct inode *inode, struct file *filp) filemap_fdatawait(inode->i_mapping); if (fidnum >= 0) { - fid->fidopen--; dprintk(DEBUG_VFS, "fidopen: %d v9f->fid: %d\n", fid->fidopen, fid->fid); - if (fid->fidopen == 0) { - if (v9fs_t_clunk(v9ses, fidnum, NULL)) - dprintk(DEBUG_ERROR, "clunk failed\n"); + if (v9fs_t_clunk(v9ses, fidnum, NULL)) + dprintk(DEBUG_ERROR, "clunk failed\n"); - v9fs_put_idpool(fid->fid, &v9ses->fidpool); - } + v9fs_put_idpool(fid->fid, &v9ses->fidpool); kfree(fid->rdir_fcall); + kfree(fid); filp->private_data = NULL; - v9fs_fid_destroy(fid); } d_drop(filp->f_dentry); diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 1f8ae7d580a..bbc3cc63854 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -53,30 +53,36 @@ int v9fs_file_open(struct inode *inode, struct file *file) { struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); - struct v9fs_fid *v9fid = v9fs_fid_lookup(file->f_dentry, FID_WALK); - struct v9fs_fid *v9newfid = NULL; + struct v9fs_fid *v9fid, *fid; struct v9fs_fcall *fcall = NULL; int open_mode = 0; unsigned int iounit = 0; int newfid = -1; long result = -1; - dprintk(DEBUG_VFS, "inode: %p file: %p v9fid= %p\n", inode, file, - v9fid); + dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file); + + v9fid = v9fs_fid_get_created(file->f_dentry); + if (!v9fid) + v9fid = v9fs_fid_lookup(file->f_dentry); if (!v9fid) { - struct dentry *dentry = file->f_dentry; dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n"); + return -EBADF; + } - /* XXX - some duplication from lookup, generalize later */ - /* basically vfs_lookup is too heavy weight */ - v9fid = v9fs_fid_lookup(file->f_dentry, FID_OP); - if (!v9fid) - return -EBADF; + if (!v9fid->fidcreate) { + fid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); + if (fid == NULL) { + dprintk(DEBUG_ERROR, "Out of Memory\n"); + return -ENOMEM; + } - v9fid = v9fs_fid_lookup(dentry->d_parent, FID_WALK); - if (!v9fid) - return -EBADF; + fid->fidopen = 0; + fid->fidcreate = 0; + fid->fidclunked = 0; + fid->iounit = 0; + fid->v9ses = v9ses; newfid = v9fs_get_idpool(&v9ses->fidpool); if (newfid < 0) { @@ -85,58 +91,16 @@ int v9fs_file_open(struct inode *inode, struct file *file) } result = - v9fs_t_walk(v9ses, v9fid->fid, newfid, - (char *)file->f_dentry->d_name.name, NULL); + v9fs_t_walk(v9ses, v9fid->fid, newfid, NULL, NULL); + if (result < 0) { v9fs_put_idpool(newfid, &v9ses->fidpool); dprintk(DEBUG_ERROR, "rewalk didn't work\n"); return -EBADF; } - v9fid = v9fs_fid_create(dentry); - if (v9fid == NULL) { - dprintk(DEBUG_ERROR, "couldn't insert\n"); - return -ENOMEM; - } - v9fid->fid = newfid; - } - - if (v9fid->fidcreate) { - /* create case */ - newfid = v9fid->fid; - iounit = v9fid->iounit; - v9fid->fidcreate = 0; - } else { - if (!S_ISDIR(inode->i_mode)) - newfid = v9fid->fid; - else { - newfid = v9fs_get_idpool(&v9ses->fidpool); - if (newfid < 0) { - eprintk(KERN_WARNING, "allocation failed\n"); - return -ENOSPC; - } - /* This would be a somewhat critical clone */ - result = - v9fs_t_walk(v9ses, v9fid->fid, newfid, NULL, - &fcall); - if (result < 0) { - dprintk(DEBUG_ERROR, "clone error: %s\n", - FCALL_ERROR(fcall)); - kfree(fcall); - return result; - } - - v9newfid = v9fs_fid_create(file->f_dentry); - v9newfid->fid = newfid; - v9newfid->qid = v9fid->qid; - v9newfid->iounit = v9fid->iounit; - v9newfid->fidopen = 0; - v9newfid->fidclunked = 0; - v9newfid->v9ses = v9ses; - v9fid = v9newfid; - kfree(fcall); - } - + fid->fid |