NFSv4: bump/drop the nlink count on the parent dir when we mkdir/rmdir
Ensure that we always bump or drop the nlink count on the parent directory when we do a mkdir or a rmdir(). This needs to be done by hand as we don't have pre/post op attributes. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
This commit is contained in:
parent
c16467dc03
commit
3c591175d6
@ -1078,12 +1078,26 @@ int nfs4_call_sync(struct rpc_clnt *clnt,
|
||||
return nfs4_call_sync_sequence(clnt, server, msg, args, res);
|
||||
}
|
||||
|
||||
static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo,
|
||||
static void
|
||||
nfs4_inc_nlink_locked(struct inode *inode)
|
||||
{
|
||||
NFS_I(inode)->cache_validity |= NFS_INO_INVALID_OTHER;
|
||||
inc_nlink(inode);
|
||||
}
|
||||
|
||||
static void
|
||||
nfs4_dec_nlink_locked(struct inode *inode)
|
||||
{
|
||||
NFS_I(inode)->cache_validity |= NFS_INO_INVALID_OTHER;
|
||||
drop_nlink(inode);
|
||||
}
|
||||
|
||||
static void
|
||||
update_changeattr_locked(struct inode *dir, struct nfs4_change_info *cinfo,
|
||||
unsigned long timestamp)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(dir);
|
||||
|
||||
spin_lock(&dir->i_lock);
|
||||
nfsi->cache_validity |= NFS_INO_INVALID_CTIME
|
||||
| NFS_INO_INVALID_MTIME
|
||||
| NFS_INO_INVALID_DATA;
|
||||
@ -1100,6 +1114,14 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo,
|
||||
nfsi->read_cache_jiffies = timestamp;
|
||||
nfsi->attr_gencount = nfs_inc_attr_generation_counter();
|
||||
nfs_fscache_invalidate(dir);
|
||||
}
|
||||
|
||||
static void
|
||||
update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo,
|
||||
unsigned long timestamp)
|
||||
{
|
||||
spin_lock(&dir->i_lock);
|
||||
update_changeattr_locked(dir, cinfo, timestamp);
|
||||
spin_unlock(&dir->i_lock);
|
||||
}
|
||||
|
||||
@ -4248,7 +4270,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
|
||||
return status;
|
||||
}
|
||||
|
||||
static int _nfs4_proc_remove(struct inode *dir, const struct qstr *name)
|
||||
static int
|
||||
_nfs4_proc_remove(struct inode *dir, const struct qstr *name, u32 ftype)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(dir);
|
||||
struct nfs_removeargs args = {
|
||||
@ -4267,8 +4290,14 @@ static int _nfs4_proc_remove(struct inode *dir, const struct qstr *name)
|
||||
int status;
|
||||
|
||||
status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
|
||||
if (status == 0)
|
||||
update_changeattr(dir, &res.cinfo, timestamp);
|
||||
if (status == 0) {
|
||||
spin_lock(&dir->i_lock);
|
||||
update_changeattr_locked(dir, &res.cinfo, timestamp);
|
||||
/* Removing a directory decrements nlink in the parent */
|
||||
if (ftype == NF4DIR && dir->i_nlink > 2)
|
||||
nfs4_dec_nlink_locked(dir);
|
||||
spin_unlock(&dir->i_lock);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -4285,7 +4314,7 @@ static int nfs4_proc_remove(struct inode *dir, struct dentry *dentry)
|
||||
nfs4_inode_make_writeable(inode);
|
||||
}
|
||||
do {
|
||||
err = _nfs4_proc_remove(dir, &dentry->d_name);
|
||||
err = _nfs4_proc_remove(dir, &dentry->d_name, NF4REG);
|
||||
trace_nfs4_remove(dir, &dentry->d_name, err);
|
||||
err = nfs4_handle_exception(NFS_SERVER(dir), err,
|
||||
&exception);
|
||||
@ -4299,7 +4328,7 @@ static int nfs4_proc_rmdir(struct inode *dir, const struct qstr *name)
|
||||
int err;
|
||||
|
||||
do {
|
||||
err = _nfs4_proc_remove(dir, name);
|
||||
err = _nfs4_proc_remove(dir, name, NF4DIR);
|
||||
trace_nfs4_remove(dir, name, err);
|
||||
err = nfs4_handle_exception(NFS_SERVER(dir), err,
|
||||
&exception);
|
||||
@ -4503,8 +4532,13 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_
|
||||
int status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &data->msg,
|
||||
&data->arg.seq_args, &data->res.seq_res, 1);
|
||||
if (status == 0) {
|
||||
update_changeattr(dir, &data->res.dir_cinfo,
|
||||
spin_lock(&dir->i_lock);
|
||||
update_changeattr_locked(dir, &data->res.dir_cinfo,
|
||||
data->res.fattr->time_start);
|
||||
/* Creating a directory bumps nlink in the parent */
|
||||
if (data->arg.ftype == NF4DIR)
|
||||
nfs4_inc_nlink_locked(dir);
|
||||
spin_unlock(&dir->i_lock);
|
||||
status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, data->res.label);
|
||||
}
|
||||
return status;
|
||||
|
Loading…
Reference in New Issue
Block a user