diff options
Diffstat (limited to 'fs/9p')
-rw-r--r-- | fs/9p/fid.c | 12 | ||||
-rw-r--r-- | fs/9p/v9fs.c | 21 | ||||
-rw-r--r-- | fs/9p/v9fs.h | 1 | ||||
-rw-r--r-- | fs/9p/vfs_dir.c | 2 | ||||
-rw-r--r-- | fs/9p/vfs_inode.c | 9 | ||||
-rw-r--r-- | fs/9p/vfs_super.c | 3 |
6 files changed, 41 insertions, 7 deletions
diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 82ee460..7317b39 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -111,7 +111,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) { int i, n, l, clone, any, access; u32 uid; - struct p9_fid *fid; + struct p9_fid *fid, *old_fid = NULL; struct dentry *d, *ds; struct v9fs_session_info *v9ses; char **wnames, *uname; @@ -184,10 +184,18 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) l = min(n - i, P9_MAXWELEM); fid = p9_client_walk(fid, l, &wnames[i], clone); if (IS_ERR(fid)) { + if (old_fid) { + /* + * If we fail, clunk fid which are mapping + * to path component and not the last component + * of the path. + */ + p9_client_clunk(old_fid); + } kfree(wnames); return fid; } - + old_fid = fid; i += l; clone = 0; } diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index cb57d33..5c5bc84 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -242,7 +242,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, list_add(&v9ses->slist, &v9fs_sessionlist); spin_unlock(&v9fs_sessionlist_lock); - v9ses->flags = V9FS_PROTO_2000U | V9FS_ACCESS_USER; + v9ses->flags = V9FS_ACCESS_USER; strcpy(v9ses->uname, V9FS_DEFUSER); strcpy(v9ses->aname, V9FS_DEFANAME); v9ses->uid = ~0; @@ -263,8 +263,10 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, goto error; } - if (!p9_is_proto_dotu(v9ses->clnt)) - v9ses->flags &= ~V9FS_PROTO_2000U; + if (p9_is_proto_dotl(v9ses->clnt)) + v9ses->flags |= V9FS_PROTO_2000L; + else if (p9_is_proto_dotu(v9ses->clnt)) + v9ses->flags |= V9FS_PROTO_2000U; v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ; @@ -341,6 +343,19 @@ void v9fs_session_cancel(struct v9fs_session_info *v9ses) { p9_client_disconnect(v9ses->clnt); } +/** + * v9fs_session_begin_cancel - Begin terminate of a session + * @v9ses: session to terminate + * + * After this call we don't allow any request other than clunk. + */ + +void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses) +{ + P9_DPRINTK(P9_DEBUG_ERROR, "begin cancel session %p\n", v9ses); + p9_client_begin_disconnect(v9ses->clnt); +} + extern int v9fs_error_init(void); static struct kobject *v9fs_kobj; diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h index 6b801d1..a0a8d3d 100644 --- a/fs/9p/v9fs.h +++ b/fs/9p/v9fs.h @@ -108,6 +108,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *, const char *, char *); void v9fs_session_close(struct v9fs_session_info *v9ses); void v9fs_session_cancel(struct v9fs_session_info *v9ses); +void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses); #define V9FS_MAGIC 0x01021997 diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index 909711f..0adfd64 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c @@ -131,6 +131,8 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) rdir = (struct p9_rdir *) fid->rdir; err = mutex_lock_interruptible(&rdir->mutex); + if (err) + return err; while (err == 0) { if (rdir->tail == rdir->head) { err = v9fs_file_readn(filp, rdir->buf, NULL, diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 63c2b5a..f2434fc 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -432,6 +432,7 @@ error: static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) { + int retval; struct inode *file_inode; struct v9fs_session_info *v9ses; struct p9_fid *v9fid; @@ -445,7 +446,10 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) if (IS_ERR(v9fid)) return PTR_ERR(v9fid); - return p9_client_remove(v9fid); + retval = p9_client_remove(v9fid); + if (!retval) + drop_nlink(file_inode); + return retval; } static int @@ -657,6 +661,9 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, P9_DPRINTK(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n", dir, dentry->d_name.name, dentry, nameidata); + if (dentry->d_name.len > NAME_MAX) + return ERR_PTR(-ENAMETOOLONG); + sb = dir->i_sb; v9ses = v9fs_inode2v9ses(dir); dfid = v9fs_fid_lookup(dentry->d_parent); diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index a271549d..491108b 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -194,6 +194,7 @@ static void v9fs_kill_super(struct super_block *s) kill_anon_super(s); + v9fs_session_cancel(v9ses); v9fs_session_close(v9ses); kfree(v9ses); s->s_fs_info = NULL; @@ -206,7 +207,7 @@ v9fs_umount_begin(struct super_block *sb) struct v9fs_session_info *v9ses; v9ses = sb->s_fs_info; - v9fs_session_cancel(v9ses); + v9fs_session_begin_cancel(v9ses); } static const struct super_operations v9fs_super_ops = { |