Commit 3c591175 authored by Trond Myklebust's avatar Trond Myklebust Committed by Anna Schumaker

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: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent c16467dc
...@@ -1078,12 +1078,26 @@ int nfs4_call_sync(struct rpc_clnt *clnt, ...@@ -1078,12 +1078,26 @@ int nfs4_call_sync(struct rpc_clnt *clnt,
return nfs4_call_sync_sequence(clnt, server, msg, args, res); 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) unsigned long timestamp)
{ {
struct nfs_inode *nfsi = NFS_I(dir); struct nfs_inode *nfsi = NFS_I(dir);
spin_lock(&dir->i_lock);
nfsi->cache_validity |= NFS_INO_INVALID_CTIME nfsi->cache_validity |= NFS_INO_INVALID_CTIME
| NFS_INO_INVALID_MTIME | NFS_INO_INVALID_MTIME
| NFS_INO_INVALID_DATA; | NFS_INO_INVALID_DATA;
...@@ -1100,6 +1114,14 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo, ...@@ -1100,6 +1114,14 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo,
nfsi->read_cache_jiffies = timestamp; nfsi->read_cache_jiffies = timestamp;
nfsi->attr_gencount = nfs_inc_attr_generation_counter(); nfsi->attr_gencount = nfs_inc_attr_generation_counter();
nfs_fscache_invalidate(dir); 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); spin_unlock(&dir->i_lock);
} }
...@@ -4248,7 +4270,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, ...@@ -4248,7 +4270,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
return status; 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_server *server = NFS_SERVER(dir);
struct nfs_removeargs args = { struct nfs_removeargs args = {
...@@ -4267,8 +4290,14 @@ static int _nfs4_proc_remove(struct inode *dir, const struct qstr *name) ...@@ -4267,8 +4290,14 @@ static int _nfs4_proc_remove(struct inode *dir, const struct qstr *name)
int status; int status;
status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1); status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
if (status == 0) if (status == 0) {
update_changeattr(dir, &res.cinfo, timestamp); 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; return status;
} }
...@@ -4285,7 +4314,7 @@ static int nfs4_proc_remove(struct inode *dir, struct dentry *dentry) ...@@ -4285,7 +4314,7 @@ static int nfs4_proc_remove(struct inode *dir, struct dentry *dentry)
nfs4_inode_make_writeable(inode); nfs4_inode_make_writeable(inode);
} }
do { 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); trace_nfs4_remove(dir, &dentry->d_name, err);
err = nfs4_handle_exception(NFS_SERVER(dir), err, err = nfs4_handle_exception(NFS_SERVER(dir), err,
&exception); &exception);
...@@ -4299,7 +4328,7 @@ static int nfs4_proc_rmdir(struct inode *dir, const struct qstr *name) ...@@ -4299,7 +4328,7 @@ static int nfs4_proc_rmdir(struct inode *dir, const struct qstr *name)
int err; int err;
do { do {
err = _nfs4_proc_remove(dir, name); err = _nfs4_proc_remove(dir, name, NF4DIR);
trace_nfs4_remove(dir, name, err); trace_nfs4_remove(dir, name, err);
err = nfs4_handle_exception(NFS_SERVER(dir), err, err = nfs4_handle_exception(NFS_SERVER(dir), err,
&exception); &exception);
...@@ -4503,8 +4532,13 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_ ...@@ -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, int status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &data->msg,
&data->arg.seq_args, &data->res.seq_res, 1); &data->arg.seq_args, &data->res.seq_res, 1);
if (status == 0) { 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); 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); status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, data->res.label);
} }
return status; return status;
......
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