Commit 70990afa authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '9p-for-5.11-rc1' of git://github.com/martinetd/linux

Pull 9p update from Dominique Martinet:

 - fix long-standing limitation on open-unlink-fop pattern

 - add refcount to p9_fid (fixes the above and will allow for more
   cleanups and simplifications in the future)

* tag '9p-for-5.11-rc1' of git://github.com/martinetd/linux:
  9p: Remove unnecessary IS_ERR() check
  9p: Uninitialized variable in v9fs_writeback_fid()
  9p: Fix writeback fid incorrectly being attached to dentry
  9p: apply review requests for fid refcounting
  9p: add refcount to p9_fid struct
  fs/9p: search open fids first
  fs/9p: track open fids
  fs/9p: fix create-unlink-getattr idiom
parents e37b12e4 cfd1d0f5
...@@ -38,6 +38,48 @@ void v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid) ...@@ -38,6 +38,48 @@ void v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid)
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
} }
/**
* v9fs_fid_find_inode - search for an open fid off of the inode list
* @inode: return a fid pointing to a specific inode
* @uid: return a fid belonging to the specified user
*
*/
static struct p9_fid *v9fs_fid_find_inode(struct inode *inode, kuid_t uid)
{
struct hlist_head *h;
struct p9_fid *fid, *ret = NULL;
p9_debug(P9_DEBUG_VFS, " inode: %p\n", inode);
spin_lock(&inode->i_lock);
h = (struct hlist_head *)&inode->i_private;
hlist_for_each_entry(fid, h, ilist) {
if (uid_eq(fid->uid, uid)) {
refcount_inc(&fid->count);
ret = fid;
break;
}
}
spin_unlock(&inode->i_lock);
return ret;
}
/**
* v9fs_open_fid_add - add an open fid to an inode
* @dentry: inode that the fid is being added to
* @fid: fid to add
*
*/
void v9fs_open_fid_add(struct inode *inode, struct p9_fid *fid)
{
spin_lock(&inode->i_lock);
hlist_add_head(&fid->ilist, (struct hlist_head *)&inode->i_private);
spin_unlock(&inode->i_lock);
}
/** /**
* v9fs_fid_find - retrieve a fid that belongs to the specified uid * v9fs_fid_find - retrieve a fid that belongs to the specified uid
* @dentry: dentry to look for fid in * @dentry: dentry to look for fid in
...@@ -54,13 +96,18 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any) ...@@ -54,13 +96,18 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any)
dentry, dentry, from_kuid(&init_user_ns, uid), dentry, dentry, from_kuid(&init_user_ns, uid),
any); any);
ret = NULL; ret = NULL;
if (d_inode(dentry))
ret = v9fs_fid_find_inode(d_inode(dentry), uid);
/* we'll recheck under lock if there's anything to look in */ /* we'll recheck under lock if there's anything to look in */
if (dentry->d_fsdata) { if (!ret && dentry->d_fsdata) {
struct hlist_head *h = (struct hlist_head *)&dentry->d_fsdata; struct hlist_head *h = (struct hlist_head *)&dentry->d_fsdata;
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
hlist_for_each_entry(fid, h, dlist) { hlist_for_each_entry(fid, h, dlist) {
if (any || uid_eq(fid->uid, uid)) { if (any || uid_eq(fid->uid, uid)) {
ret = fid; ret = fid;
refcount_inc(&ret->count);
break; break;
} }
} }
...@@ -122,7 +169,10 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry, ...@@ -122,7 +169,10 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry,
fid = v9fs_fid_find(ds, uid, any); fid = v9fs_fid_find(ds, uid, any);
if (fid) { if (fid) {
/* Found the parent fid do a lookup with that */ /* Found the parent fid do a lookup with that */
fid = p9_client_walk(fid, 1, &dentry->d_name.name, 1); struct p9_fid *ofid = fid;
fid = p9_client_walk(ofid, 1, &dentry->d_name.name, 1);
p9_client_clunk(ofid);
goto fid_out; goto fid_out;
} }
up_read(&v9ses->rename_sem); up_read(&v9ses->rename_sem);
...@@ -147,8 +197,10 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry, ...@@ -147,8 +197,10 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry,
v9fs_fid_add(dentry->d_sb->s_root, fid); v9fs_fid_add(dentry->d_sb->s_root, fid);
} }
/* If we are root ourself just return that */ /* If we are root ourself just return that */
if (dentry->d_sb->s_root == dentry) if (dentry->d_sb->s_root == dentry) {
refcount_inc(&fid->count);
return fid; return fid;
}
/* /*
* Do a multipath walk with attached root. * Do a multipath walk with attached root.
* When walking parent we need to make sure we * When walking parent we need to make sure we
...@@ -195,6 +247,7 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry, ...@@ -195,6 +247,7 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry,
fid = ERR_PTR(-ENOENT); fid = ERR_PTR(-ENOENT);
} else { } else {
__add_fid(dentry, fid); __add_fid(dentry, fid);
refcount_inc(&fid->count);
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
} }
} }
...@@ -245,11 +298,13 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) ...@@ -245,11 +298,13 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
struct p9_fid *v9fs_writeback_fid(struct dentry *dentry) struct p9_fid *v9fs_writeback_fid(struct dentry *dentry)
{ {
int err; int err;
struct p9_fid *fid; struct p9_fid *fid, *ofid;
fid = clone_fid(v9fs_fid_lookup_with_uid(dentry, GLOBAL_ROOT_UID, 0)); ofid = v9fs_fid_lookup_with_uid(dentry, GLOBAL_ROOT_UID, 0);
fid = clone_fid(ofid);
if (IS_ERR(fid)) if (IS_ERR(fid))
goto error_out; goto error_out;
p9_client_clunk(ofid);
/* /*
* writeback fid will only be used to write back the * writeback fid will only be used to write back the
* dirty pages. We always request for the open fid in read-write * dirty pages. We always request for the open fid in read-write
......
...@@ -15,12 +15,21 @@ static inline struct p9_fid *v9fs_parent_fid(struct dentry *dentry) ...@@ -15,12 +15,21 @@ static inline struct p9_fid *v9fs_parent_fid(struct dentry *dentry)
} }
void v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid); void v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid);
struct p9_fid *v9fs_writeback_fid(struct dentry *dentry); struct p9_fid *v9fs_writeback_fid(struct dentry *dentry);
void v9fs_open_fid_add(struct inode *inode, struct p9_fid *fid);
static inline struct p9_fid *clone_fid(struct p9_fid *fid) static inline struct p9_fid *clone_fid(struct p9_fid *fid)
{ {
return IS_ERR(fid) ? fid : p9_client_walk(fid, 0, NULL, 1); return IS_ERR(fid) ? fid : p9_client_walk(fid, 0, NULL, 1);
} }
static inline struct p9_fid *v9fs_fid_clone(struct dentry *dentry) static inline struct p9_fid *v9fs_fid_clone(struct dentry *dentry)
{ {
return clone_fid(v9fs_fid_lookup(dentry)); struct p9_fid *fid, *nfid;
fid = v9fs_fid_lookup(dentry);
if (!fid || IS_ERR(fid))
return fid;
nfid = clone_fid(fid);
p9_client_clunk(fid);
return nfid;
} }
#endif #endif
...@@ -85,6 +85,8 @@ static int v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags) ...@@ -85,6 +85,8 @@ static int v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
retval = v9fs_refresh_inode_dotl(fid, inode); retval = v9fs_refresh_inode_dotl(fid, inode);
else else
retval = v9fs_refresh_inode(fid, inode); retval = v9fs_refresh_inode(fid, inode);
p9_client_clunk(fid);
if (retval == -ENOENT) if (retval == -ENOENT)
return 0; return 0;
if (retval < 0) if (retval < 0)
......
...@@ -210,8 +210,12 @@ int v9fs_dir_release(struct inode *inode, struct file *filp) ...@@ -210,8 +210,12 @@ int v9fs_dir_release(struct inode *inode, struct file *filp)
fid = filp->private_data; fid = filp->private_data;
p9_debug(P9_DEBUG_VFS, "inode: %p filp: %p fid: %d\n", p9_debug(P9_DEBUG_VFS, "inode: %p filp: %p fid: %d\n",
inode, filp, fid ? fid->fid : -1); inode, filp, fid ? fid->fid : -1);
if (fid) if (fid) {
spin_lock(&inode->i_lock);
hlist_del(&fid->ilist);
spin_unlock(&inode->i_lock);
p9_client_clunk(fid); p9_client_clunk(fid);
}
return 0; return 0;
} }
......
...@@ -46,7 +46,7 @@ int v9fs_file_open(struct inode *inode, struct file *file) ...@@ -46,7 +46,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
int err; int err;
struct v9fs_inode *v9inode; struct v9fs_inode *v9inode;
struct v9fs_session_info *v9ses; struct v9fs_session_info *v9ses;
struct p9_fid *fid; struct p9_fid *fid, *writeback_fid;
int omode; int omode;
p9_debug(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file); p9_debug(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file);
...@@ -85,17 +85,18 @@ int v9fs_file_open(struct inode *inode, struct file *file) ...@@ -85,17 +85,18 @@ int v9fs_file_open(struct inode *inode, struct file *file)
* because we want write after unlink usecase * because we want write after unlink usecase
* to work. * to work.
*/ */
fid = v9fs_writeback_fid(file_dentry(file)); writeback_fid = v9fs_writeback_fid(file_dentry(file));
if (IS_ERR(fid)) { if (IS_ERR(fid)) {
err = PTR_ERR(fid); err = PTR_ERR(fid);
mutex_unlock(&v9inode->v_mutex); mutex_unlock(&v9inode->v_mutex);
goto out_error; goto out_error;
} }
v9inode->writeback_fid = (void *) fid; v9inode->writeback_fid = (void *) writeback_fid;
} }
mutex_unlock(&v9inode->v_mutex); mutex_unlock(&v9inode->v_mutex);
if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
v9fs_cache_inode_set_cookie(inode, file); v9fs_cache_inode_set_cookie(inode, file);
v9fs_open_fid_add(inode, fid);
return 0; return 0;
out_error: out_error:
p9_client_clunk(file->private_data); p9_client_clunk(file->private_data);
......
...@@ -256,6 +256,7 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses, ...@@ -256,6 +256,7 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses,
inode->i_rdev = rdev; inode->i_rdev = rdev;
inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
inode->i_mapping->a_ops = &v9fs_addr_operations; inode->i_mapping->a_ops = &v9fs_addr_operations;
inode->i_private = NULL;
switch (mode & S_IFMT) { switch (mode & S_IFMT) {
case S_IFIFO: case S_IFIFO:
...@@ -550,6 +551,7 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags) ...@@ -550,6 +551,7 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags)
if (v9fs_proto_dotl(v9ses)) if (v9fs_proto_dotl(v9ses))
retval = p9_client_unlinkat(dfid, dentry->d_name.name, retval = p9_client_unlinkat(dfid, dentry->d_name.name,
v9fs_at_to_dotl_flags(flags)); v9fs_at_to_dotl_flags(flags));
p9_client_clunk(dfid);
if (retval == -EOPNOTSUPP) { if (retval == -EOPNOTSUPP) {
/* Try the one based on path */ /* Try the one based on path */
v9fid = v9fs_fid_clone(dentry); v9fid = v9fs_fid_clone(dentry);
...@@ -570,6 +572,10 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags) ...@@ -570,6 +572,10 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags)
v9fs_invalidate_inode_attr(inode); v9fs_invalidate_inode_attr(inode);
v9fs_invalidate_inode_attr(dir); v9fs_invalidate_inode_attr(dir);
/* invalidate all fids associated with dentry */
/* NOTE: This will not include open fids */
dentry->d_op->d_release(dentry);
} }
return retval; return retval;
} }
...@@ -590,14 +596,12 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, ...@@ -590,14 +596,12 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
{ {
int err; int err;
const unsigned char *name; const unsigned char *name;
struct p9_fid *dfid, *ofid, *fid; struct p9_fid *dfid, *ofid = NULL, *fid = NULL;
struct inode *inode; struct inode *inode;
p9_debug(P9_DEBUG_VFS, "name %pd\n", dentry); p9_debug(P9_DEBUG_VFS, "name %pd\n", dentry);
err = 0; err = 0;
ofid = NULL;
fid = NULL;
name = dentry->d_name.name; name = dentry->d_name.name;
dfid = v9fs_parent_fid(dentry); dfid = v9fs_parent_fid(dentry);
if (IS_ERR(dfid)) { if (IS_ERR(dfid)) {
...@@ -611,12 +615,14 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, ...@@ -611,12 +615,14 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
if (IS_ERR(ofid)) { if (IS_ERR(ofid)) {
err = PTR_ERR(ofid); err = PTR_ERR(ofid);
p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
p9_client_clunk(dfid);
return ERR_PTR(err); return ERR_PTR(err);
} }
err = p9_client_fcreate(ofid, name, perm, mode, extension); err = p9_client_fcreate(ofid, name, perm, mode, extension);
if (err < 0) { if (err < 0) {
p9_debug(P9_DEBUG_VFS, "p9_client_fcreate failed %d\n", err); p9_debug(P9_DEBUG_VFS, "p9_client_fcreate failed %d\n", err);
p9_client_clunk(dfid);
goto error; goto error;
} }
...@@ -628,6 +634,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, ...@@ -628,6 +634,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
p9_debug(P9_DEBUG_VFS, p9_debug(P9_DEBUG_VFS,
"p9_client_walk failed %d\n", err); "p9_client_walk failed %d\n", err);
fid = NULL; fid = NULL;
p9_client_clunk(dfid);
goto error; goto error;
} }
/* /*
...@@ -638,11 +645,13 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, ...@@ -638,11 +645,13 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
err = PTR_ERR(inode); err = PTR_ERR(inode);
p9_debug(P9_DEBUG_VFS, p9_debug(P9_DEBUG_VFS,
"inode creation failed %d\n", err); "inode creation failed %d\n", err);
p9_client_clunk(dfid);
goto error; goto error;
} }
v9fs_fid_add(dentry, fid); v9fs_fid_add(dentry, fid);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
} }
p9_client_clunk(dfid);
return ofid; return ofid;
error: error:
if (ofid) if (ofid)
...@@ -755,6 +764,7 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -755,6 +764,7 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
*/ */
name = dentry->d_name.name; name = dentry->d_name.name;
fid = p9_client_walk(dfid, 1, &name, 1); fid = p9_client_walk(dfid, 1, &name, 1);
p9_client_clunk(dfid);
if (fid == ERR_PTR(-ENOENT)) if (fid == ERR_PTR(-ENOENT))
inode = NULL; inode = NULL;
else if (IS_ERR(fid)) else if (IS_ERR(fid))
...@@ -792,6 +802,7 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -792,6 +802,7 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
struct v9fs_session_info *v9ses; struct v9fs_session_info *v9ses;
struct p9_fid *fid, *inode_fid; struct p9_fid *fid, *inode_fid;
struct dentry *res = NULL; struct dentry *res = NULL;
struct inode *inode;
if (d_in_lookup(dentry)) { if (d_in_lookup(dentry)) {
res = v9fs_vfs_lookup(dir, dentry, 0); res = v9fs_vfs_lookup(dir, dentry, 0);
...@@ -820,7 +831,8 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -820,7 +831,8 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
} }
v9fs_invalidate_inode_attr(dir); v9fs_invalidate_inode_attr(dir);
v9inode = V9FS_I(d_inode(dentry)); inode = d_inode(dentry);
v9inode = V9FS_I(inode);
mutex_lock(&v9inode->v_mutex); mutex_lock(&v9inode->v_mutex);
if ((v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) && if ((v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) &&
!v9inode->writeback_fid && !v9inode->writeback_fid &&
...@@ -848,6 +860,7 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -848,6 +860,7 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
file->private_data = fid; file->private_data = fid;
if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
v9fs_cache_inode_set_cookie(d_inode(dentry), file); v9fs_cache_inode_set_cookie(d_inode(dentry), file);
v9fs_open_fid_add(inode, fid);
file->f_mode |= FMODE_CREATED; file->f_mode |= FMODE_CREATED;
out: out:
...@@ -902,7 +915,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -902,7 +915,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *old_inode; struct inode *old_inode;
struct inode *new_inode; struct inode *new_inode;
struct v9fs_session_info *v9ses; struct v9fs_session_info *v9ses;
struct p9_fid *oldfid; struct p9_fid *oldfid, *dfid;
struct p9_fid *olddirfid; struct p9_fid *olddirfid;
struct p9_fid *newdirfid; struct p9_fid *newdirfid;
struct p9_wstat wstat; struct p9_wstat wstat;
...@@ -919,13 +932,20 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -919,13 +932,20 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (IS_ERR(oldfid)) if (IS_ERR(oldfid))
return PTR_ERR(oldfid); return PTR_ERR(oldfid);
olddirfid = clone_fid(v9fs_parent_fid(old_dentry)); dfid = v9fs_parent_fid(old_dentry);
olddirfid = clone_fid(dfid);
if (dfid && !IS_ERR(dfid))
p9_client_clunk(dfid);
if (IS_ERR(olddirfid)) { if (IS_ERR(olddirfid)) {
retval = PTR_ERR(olddirfid); retval = PTR_ERR(olddirfid);
goto done; goto done;
} }
newdirfid = clone_fid(v9fs_parent_fid(new_dentry)); dfid = v9fs_parent_fid(new_dentry);
newdirfid = clone_fid(dfid);
p9_client_clunk(dfid);
if (IS_ERR(newdirfid)) { if (IS_ERR(newdirfid)) {
retval = PTR_ERR(newdirfid); retval = PTR_ERR(newdirfid);
goto clunk_olddir; goto clunk_olddir;
...@@ -982,6 +1002,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -982,6 +1002,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
p9_client_clunk(olddirfid); p9_client_clunk(olddirfid);
done: done:
p9_client_clunk(oldfid);
return retval; return retval;
} }
...@@ -1014,6 +1035,7 @@ v9fs_vfs_getattr(const struct path *path, struct kstat *stat, ...@@ -1014,6 +1035,7 @@ v9fs_vfs_getattr(const struct path *path, struct kstat *stat,
return PTR_ERR(fid); return PTR_ERR(fid);
st = p9_client_stat(fid); st = p9_client_stat(fid);
p9_client_clunk(fid);
if (IS_ERR(st)) if (IS_ERR(st))
return PTR_ERR(st); return PTR_ERR(st);
...@@ -1034,7 +1056,7 @@ v9fs_vfs_getattr(const struct path *path, struct kstat *stat, ...@@ -1034,7 +1056,7 @@ v9fs_vfs_getattr(const struct path *path, struct kstat *stat,
static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
{ {
int retval; int retval, use_dentry = 0;
struct v9fs_session_info *v9ses; struct v9fs_session_info *v9ses;
struct p9_fid *fid = NULL; struct p9_fid *fid = NULL;
struct p9_wstat wstat; struct p9_wstat wstat;
...@@ -1050,8 +1072,10 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) ...@@ -1050,8 +1072,10 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
fid = iattr->ia_file->private_data; fid = iattr->ia_file->private_data;
WARN_ON(!fid); WARN_ON(!fid);
} }
if (!fid) if (!fid) {
fid = v9fs_fid_lookup(dentry); fid = v9fs_fid_lookup(dentry);
use_dentry = 1;
}
if(IS_ERR(fid)) if(IS_ERR(fid))
return PTR_ERR(fid); return PTR_ERR(fid);
...@@ -1081,6 +1105,10 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) ...@@ -1081,6 +1105,10 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
filemap_write_and_wait(d_inode(dentry)->i_mapping); filemap_write_and_wait(d_inode(dentry)->i_mapping);
retval = p9_client_wstat(fid, &wstat); retval = p9_client_wstat(fid, &wstat);
if (use_dentry)
p9_client_clunk(fid);
if (retval < 0) if (retval < 0)
return retval; return retval;
...@@ -1205,6 +1233,7 @@ static const char *v9fs_vfs_get_link(struct dentry *dentry, ...@@ -1205,6 +1233,7 @@ static const char *v9fs_vfs_get_link(struct dentry *dentry,
return ERR_PTR(-EBADF); return ERR_PTR(-EBADF);
st = p9_client_stat(fid); st = p9_client_stat(fid);
p9_client_clunk(fid);
if (IS_ERR(st)) if (IS_ERR(st))
return ERR_CAST(st); return ERR_CAST(st);
......
...@@ -296,6 +296,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, ...@@ -296,6 +296,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
/* instantiate inode and assign the unopened fid to the dentry */ /* instantiate inode and assign the unopened fid to the dentry */
fid = p9_client_walk(dfid, 1, &name, 1); fid = p9_client_walk(dfid, 1, &name, 1);
p9_client_clunk(dfid);
if (IS_ERR(fid)) { if (IS_ERR(fid)) {
err = PTR_ERR(fid); err = PTR_ERR(fid);
p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
...@@ -342,6 +343,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, ...@@ -342,6 +343,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
file->private_data = ofid; file->private_data = ofid;
if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
v9fs_cache_inode_set_cookie(inode, file); v9fs_cache_inode_set_cookie(inode, file);
v9fs_open_fid_add(inode, ofid);
file->f_mode |= FMODE_CREATED; file->f_mode |= FMODE_CREATED;
out: out:
v9fs_put_acl(dacl, pacl); v9fs_put_acl(dacl, pacl);
...@@ -407,7 +409,6 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, ...@@ -407,7 +409,6 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid); err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid);
if (err < 0) if (err < 0)
goto error; goto error;
fid = p9_client_walk(dfid, 1, &name, 1); fid = p9_client_walk(dfid, 1, &name, 1);
if (IS_ERR(fid)) { if (IS_ERR(fid)) {
err = PTR_ERR(fid); err = PTR_ERR(fid);
...@@ -451,6 +452,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, ...@@ -451,6 +452,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
if (fid) if (fid)
p9_client_clunk(fid); p9_client_clunk(fid);
v9fs_put_acl(dacl, pacl); v9fs_put_acl(dacl, pacl);
p9_client_clunk(dfid);
return err; return err;
} }
...@@ -478,6 +480,7 @@ v9fs_vfs_getattr_dotl(const struct path *path, struct kstat *stat, ...@@ -478,6 +480,7 @@ v9fs_vfs_getattr_dotl(const struct path *path, struct kstat *stat,
*/ */
st = p9_client_getattr_dotl(fid, P9_STATS_ALL); st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
p9_client_clunk(fid);
if (IS_ERR(st)) if (IS_ERR(st))
return PTR_ERR(st); return PTR_ERR(st);
...@@ -539,7 +542,7 @@ static int v9fs_mapped_iattr_valid(int iattr_valid) ...@@ -539,7 +542,7 @@ static int v9fs_mapped_iattr_valid(int iattr_valid)
int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
{ {
int retval; int retval, use_dentry = 0;
struct p9_fid *fid = NULL; struct p9_fid *fid = NULL;
struct p9_iattr_dotl p9attr; struct p9_iattr_dotl p9attr;
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
...@@ -564,8 +567,10 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) ...@@ -564,8 +567,10 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
fid = iattr->ia_file->private_data; fid = iattr->ia_file->private_data;
WARN_ON(!fid); WARN_ON(!fid);
} }
if (!fid) if (!fid) {
fid = v9fs_fid_lookup(dentry); fid = v9fs_fid_lookup(dentry);
use_dentry = 1;
}
if (IS_ERR(fid)) if (IS_ERR(fid))
return PTR_ERR(fid); return PTR_ERR(fid);
...@@ -574,8 +579,11 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) ...@@ -574,8 +579,11 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
filemap_write_and_wait(inode->i_mapping); filemap_write_and_wait(inode->i_mapping);
retval = p9_client_setattr(fid, &p9attr); retval = p9_client_setattr(fid, &p9attr);
if (retval < 0) if (retval < 0) {
if (use_dentry)
p9_client_clunk(fid);
return retval; return retval;
}
if ((iattr->ia_valid & ATTR_SIZE) && if ((iattr->ia_valid & ATTR_SIZE) &&
iattr->ia_size != i_size_read(inode)) iattr->ia_size != i_size_read(inode))
...@@ -587,9 +595,15 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) ...@@ -587,9 +595,15 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
if (iattr->ia_valid & ATTR_MODE) { if (iattr->ia_valid & ATTR_MODE) {
/* We also want to update ACL when we update mode bits */ /* We also want to update ACL when we update mode bits */
retval = v9fs_acl_chmod(inode, fid); retval = v9fs_acl_chmod(inode, fid);
if (retval < 0) if (retval < 0) {
if (use_dentry)
p9_client_clunk(fid);
return retval; return retval;
}
} }
if (use_dentry)
p9_client_clunk(fid);
return 0; return 0;
} }
...@@ -741,6 +755,7 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, ...@@ -741,6 +755,7 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
if (fid) if (fid)
p9_client_clunk(fid); p9_client_clunk(fid);
p9_client_clunk(dfid);
return err; return err;
} }
...@@ -769,11 +784,15 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir, ...@@ -769,11 +784,15 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
return PTR_ERR(dfid); return PTR_ERR(dfid);
oldfid = v9fs_fid_lookup(old_dentry); oldfid = v9fs_fid_lookup(old_dentry);
if (IS_ERR(oldfid)) if (IS_ERR(oldfid)) {
p9_client_clunk(dfid);
return PTR_ERR(oldfid); return PTR_ERR(oldfid);
}
err = p9_client_link(dfid, oldfid, dentry->d_name.name); err = p9_client_link(dfid, oldfid, dentry->d_name.name);
p9_client_clunk(dfid);
p9_client_clunk(oldfid);
if (err < 0) { if (err < 0) {
p9_debug(P9_DEBUG_VFS, "p9_client_link failed %d\n", err); p9_debug(P9_DEBUG_VFS, "p9_client_link failed %d\n", err);
return err; return err;
...@@ -788,6 +807,7 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir, ...@@ -788,6 +807,7 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
return PTR_ERR(fid); return PTR_ERR(fid);
v9fs_refresh_inode_dotl(fid, d_inode(old_dentry)); v9fs_refresh_inode_dotl(fid, d_inode(old_dentry));
p9_client_clunk(fid);
} }
ihold(d_inode(old_dentry)); ihold(d_inode(old_dentry));
d_instantiate(dentry, d_inode(old_dentry)); d_instantiate(dentry, d_inode(old_dentry));
...@@ -886,6 +906,8 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode, ...@@ -886,6 +906,8 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
if (fid) if (fid)
p9_client_clunk(fid); p9_client_clunk(fid);
v9fs_put_acl(dacl, pacl); v9fs_put_acl(dacl, pacl);
p9_client_clunk(dfid);
return err; return err;
} }
...@@ -914,6 +936,7 @@ v9fs_vfs_get_link_dotl(struct dentry *dentry, ...@@ -914,6 +936,7 @@ v9fs_vfs_get_link_dotl(struct dentry *dentry,
if (IS_ERR(fid)) if (IS_ERR(fid))
return ERR_CAST(fid); return ERR_CAST(fid);
retval = p9_client_readlink(fid, &target); retval = p9_client_readlink(fid, &target);
p9_client_clunk(fid);
if (retval) if (retval)
return ERR_PTR(retval); return ERR_PTR(retval);
set_delayed_call(done, kfree_link, target); set_delayed_call(done, kfree_link, target);
......
...@@ -268,6 +268,7 @@ static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf) ...@@ -268,6 +268,7 @@ static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf)
} }
res = simple_statfs(dentry, buf); res = simple_statfs(dentry, buf);
done: done:
p9_client_clunk(fid);
return res; return res;
} }
......
...@@ -71,14 +71,17 @@ ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name, ...@@ -71,14 +71,17 @@ ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name,
void *buffer, size_t buffer_size) void *buffer, size_t buffer_size)
{ {
struct p9_fid *fid; struct p9_fid *fid;
int ret;
p9_debug(P9_DEBUG_VFS, "name = %s value_len = %zu\n", p9_debug(P9_DEBUG_VFS, "name = %s value_len = %zu\n",
name, buffer_size); name, buffer_size);
fid = v9fs_fid_lookup(dentry); fid = v9fs_fid_lookup(dentry);
if (IS_ERR(fid)) if (IS_ERR(fid))
return PTR_ERR(fid); return PTR_ERR(fid);
ret = v9fs_fid_xattr_get(fid, name, buffer, buffer_size);
p9_client_clunk(fid);
return v9fs_fid_xattr_get(fid, name, buffer, buffer_size); return ret;
} }
/* /*
...@@ -96,8 +99,15 @@ ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name, ...@@ -96,8 +99,15 @@ ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name,
int v9fs_xattr_set(struct dentry *dentry, const char *name, int v9fs_xattr_set(struct dentry *dentry, const char *name,
const void *value, size_t value_len, int flags) const void *value, size_t value_len, int flags)
{ {
struct p9_fid *fid = v9fs_fid_lookup(dentry); int ret;
return v9fs_fid_xattr_set(fid, name, value, value_len, flags); struct p9_fid *fid;
fid = v9fs_fid_lookup(dentry);
if (IS_ERR(fid))
return PTR_ERR(fid);
ret = v9fs_fid_xattr_set(fid, name, value, value_len, flags);
p9_client_clunk(fid);
return ret;
} }
int v9fs_fid_xattr_set(struct p9_fid *fid, const char *name, int v9fs_fid_xattr_set(struct p9_fid *fid, const char *name,
......
...@@ -140,10 +140,16 @@ struct p9_client { ...@@ -140,10 +140,16 @@ struct p9_client {
* *
* TODO: This needs lots of explanation. * TODO: This needs lots of explanation.
*/ */
enum fid_source {
FID_FROM_OTHER,
FID_FROM_INODE,
FID_FROM_DENTRY,
};
struct p9_fid { struct p9_fid {
struct p9_client *clnt; struct p9_client *clnt;
u32 fid; u32 fid;
refcount_t count;
int mode; int mode;
struct p9_qid qid; struct p9_qid qid;
u32 iounit; u32 iounit;
...@@ -152,6 +158,7 @@ struct p9_fid { ...@@ -152,6 +158,7 @@ struct p9_fid {
void *rdir; void *rdir;
struct hlist_node dlist; /* list of all fids attached to a dentry */ struct hlist_node dlist; /* list of all fids attached to a dentry */
struct hlist_node ilist;
}; };
/** /**
......
...@@ -903,6 +903,7 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt) ...@@ -903,6 +903,7 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt)
fid->clnt = clnt; fid->clnt = clnt;
fid->rdir = NULL; fid->rdir = NULL;
fid->fid = 0; fid->fid = 0;
refcount_set(&fid->count, 1);
idr_preload(GFP_KERNEL); idr_preload(GFP_KERNEL);
spin_lock_irq(&clnt->lock); spin_lock_irq(&clnt->lock);
...@@ -910,7 +911,6 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt) ...@@ -910,7 +911,6 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt)
GFP_NOWAIT); GFP_NOWAIT);
spin_unlock_irq(&clnt->lock); spin_unlock_irq(&clnt->lock);
idr_preload_end(); idr_preload_end();
if (!ret) if (!ret)
return fid; return fid;
...@@ -1189,7 +1189,6 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname, ...@@ -1189,7 +1189,6 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname,
p9_debug(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %ud wname[0] %s\n", p9_debug(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %ud wname[0] %s\n",
oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL); oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL);
req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid, req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid,
nwname, wnames); nwname, wnames);
if (IS_ERR(req)) { if (IS_ERR(req)) {
...@@ -1221,7 +1220,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname, ...@@ -1221,7 +1220,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname,
if (nwname) if (nwname)
memmove(&fid->qid, &wqids[nwqids - 1], sizeof(struct p9_qid)); memmove(&fid->qid, &wqids[nwqids - 1], sizeof(struct p9_qid));
else else
fid->qid = oldfid->qid; memmove(&fid->qid, &oldfid->qid, sizeof(struct p9_qid));
kfree(wqids); kfree(wqids);
return fid; return fid;
...@@ -1274,6 +1273,7 @@ int p9_client_open(struct p9_fid *fid, int mode) ...@@ -1274,6 +1273,7 @@ int p9_client_open(struct p9_fid *fid, int mode)
p9_is_proto_dotl(clnt) ? "RLOPEN" : "ROPEN", qid.type, p9_is_proto_dotl(clnt) ? "RLOPEN" : "ROPEN", qid.type,
(unsigned long long)qid.path, qid.version, iounit); (unsigned long long)qid.path, qid.version, iounit);
memmove(&fid->qid, &qid, sizeof(struct p9_qid));
fid->mode = mode; fid->mode = mode;
fid->iounit = iounit; fid->iounit = iounit;
...@@ -1319,6 +1319,7 @@ int p9_client_create_dotl(struct p9_fid *ofid, const char *name, u32 flags, u32 ...@@ -1319,6 +1319,7 @@ int p9_client_create_dotl(struct p9_fid *ofid, const char *name, u32 flags, u32
(unsigned long long)qid->path, (unsigned long long)qid->path,
qid->version, iounit); qid->version, iounit);
memmove(&ofid->qid, qid, sizeof(struct p9_qid));
ofid->mode = mode; ofid->mode = mode;
ofid->iounit = iounit; ofid->iounit = iounit;
...@@ -1364,6 +1365,7 @@ int p9_client_fcreate(struct p9_fid *fid, const char *name, u32 perm, int mode, ...@@ -1364,6 +1365,7 @@ int p9_client_fcreate(struct p9_fid *fid, const char *name, u32 perm, int mode,
(unsigned long long)qid.path, (unsigned long long)qid.path,
qid.version, iounit); qid.version, iounit);
memmove(&fid->qid, &qid, sizeof(struct p9_qid));
fid->mode = mode; fid->mode = mode;
fid->iounit = iounit; fid->iounit = iounit;
...@@ -1460,12 +1462,14 @@ int p9_client_clunk(struct p9_fid *fid) ...@@ -1460,12 +1462,14 @@ int p9_client_clunk(struct p9_fid *fid)
struct p9_req_t *req; struct p9_req_t *req;
int retries = 0; int retries = 0;
if (!fid) { if (!fid || IS_ERR(fid)) {
pr_warn("%s (%d): Trying to clunk with NULL fid\n", pr_warn("%s (%d): Trying to clunk with invalid fid\n",
__func__, task_pid_nr(current)); __func__, task_pid_nr(current));
dump_stack(); dump_stack();
return 0; return 0;
} }
if (!refcount_dec_and_test(&fid->count))
return 0;
again: again:
p9_debug(P9_DEBUG_9P, ">>> TCLUNK fid %d (try %d)\n", fid->fid, p9_debug(P9_DEBUG_9P, ">>> TCLUNK fid %d (try %d)\n", fid->fid,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment