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

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
Loading
Loading
Loading
Loading
+42 −8
Original line number Diff line number Diff line
@@ -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 @@ out:
	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;