* [PATCH v2 0/3] Fix mkdir/rmdir() in NFSv4
@ 2018-07-31 17:24 Trond Myklebust
2018-07-31 17:24 ` [PATCH v2 1/3] NFSv4: bump/drop the nlink count on the parent dir when we mkdir/rmdir Trond Myklebust
0 siblings, 1 reply; 4+ messages in thread
From: Trond Myklebust @ 2018-07-31 17:24 UTC (permalink / raw)
To: Anna Schumaker; +Cc: linux-nfs
v1:
- bump/drop the nlink count on the parent dir when we mkdir/rmdir
v2:
- Fix nlink changes on cross-directory renames
- Mark the inode change attribute up to date in update_changeattr()
Trond Myklebust (3):
NFSv4: bump/drop the nlink count on the parent dir when we mkdir/rmdir
NFSv4: Detect nlink changes on cross-directory renames too
NFSv4: Mark the inode change attribute up to date in
update_changeattr()
fs/nfs/nfs4proc.c | 80 +++++++++++++++++++++++++++++++++++++----------
1 file changed, 63 insertions(+), 17 deletions(-)
--
2.17.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/3] NFSv4: bump/drop the nlink count on the parent dir when we mkdir/rmdir
2018-07-31 17:24 [PATCH v2 0/3] Fix mkdir/rmdir() in NFSv4 Trond Myklebust
@ 2018-07-31 17:24 ` Trond Myklebust
2018-07-31 17:24 ` [PATCH v2 2/3] NFSv4: Detect nlink changes on cross-directory renames too Trond Myklebust
0 siblings, 1 reply; 4+ messages in thread
From: Trond Myklebust @ 2018-07-31 17:24 UTC (permalink / raw)
To: Anna Schumaker; +Cc: linux-nfs
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>
---
fs/nfs/nfs4proc.c | 50 +++++++++++++++++++++++++++++++++++++++--------
1 file changed, 42 insertions(+), 8 deletions(-)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 5a8190ec31a2..0d56d3662005 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1071,12 +1071,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;
+ dec_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;
@@ -1093,6 +1107,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);
}
@@ -4237,7 +4259,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 = {
@@ -4256,8 +4279,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;
}
@@ -4274,7 +4303,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);
@@ -4288,7 +4317,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);
@@ -4492,8 +4521,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;
--
2.17.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 2/3] NFSv4: Detect nlink changes on cross-directory renames too
2018-07-31 17:24 ` [PATCH v2 1/3] NFSv4: bump/drop the nlink count on the parent dir when we mkdir/rmdir Trond Myklebust
@ 2018-07-31 17:24 ` Trond Myklebust
2018-07-31 17:24 ` [PATCH v2 3/3] NFSv4: Mark the inode change attribute up to date in update_changeattr() Trond Myklebust
0 siblings, 1 reply; 4+ messages in thread
From: Trond Myklebust @ 2018-07-31 17:24 UTC (permalink / raw)
To: Anna Schumaker; +Cc: linux-nfs
If the object being renamed from one directory to another is also
a directory, then 'nlink' will change for both directories.
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
---
fs/nfs/nfs4proc.c | 35 +++++++++++++++++++++++------------
1 file changed, 23 insertions(+), 12 deletions(-)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 0d56d3662005..9d181d76c744 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1087,13 +1087,14 @@ nfs4_dec_nlink_locked(struct inode *inode)
static void
update_changeattr_locked(struct inode *dir, struct nfs4_change_info *cinfo,
- unsigned long timestamp)
+ unsigned long timestamp, unsigned long cache_validity)
{
struct nfs_inode *nfsi = NFS_I(dir);
nfsi->cache_validity |= NFS_INO_INVALID_CTIME
| NFS_INO_INVALID_MTIME
- | NFS_INO_INVALID_DATA;
+ | NFS_INO_INVALID_DATA
+ | cache_validity;
if (cinfo->atomic && cinfo->before == inode_peek_iversion_raw(dir)) {
nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE;
nfsi->attrtimeo_timestamp = jiffies;
@@ -1111,10 +1112,10 @@ update_changeattr_locked(struct inode *dir, struct nfs4_change_info *cinfo,
static void
update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo,
- unsigned long timestamp)
+ unsigned long timestamp, unsigned long cache_validity)
{
spin_lock(&dir->i_lock);
- update_changeattr_locked(dir, cinfo, timestamp);
+ update_changeattr_locked(dir, cinfo, timestamp, cache_validity);
spin_unlock(&dir->i_lock);
}
@@ -2503,7 +2504,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data,
if (data->file_created ||
inode_peek_iversion_raw(dir) != o_res->cinfo.after)
update_changeattr(dir, &o_res->cinfo,
- o_res->f_attr->time_start);
+ o_res->f_attr->time_start, 0);
}
if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0)
server->caps &= ~NFS_CAP_POSIX_LOCK;
@@ -4281,7 +4282,7 @@ _nfs4_proc_remove(struct inode *dir, const struct qstr *name, u32 ftype)
status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
if (status == 0) {
spin_lock(&dir->i_lock);
- update_changeattr_locked(dir, &res.cinfo, timestamp);
+ update_changeattr_locked(dir, &res.cinfo, timestamp, 0);
/* Removing a directory decrements nlink in the parent */
if (ftype == NF4DIR && dir->i_nlink > 2)
nfs4_dec_nlink_locked(dir);
@@ -4361,7 +4362,8 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
&data->timeout) == -EAGAIN)
return 0;
if (task->tk_status == 0)
- update_changeattr(dir, &res->cinfo, res->dir_attr->time_start);
+ update_changeattr(dir, &res->cinfo,
+ res->dir_attr->time_start, 0);
return 1;
}
@@ -4403,9 +4405,18 @@ static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
return 0;
if (task->tk_status == 0) {
- update_changeattr(old_dir, &res->old_cinfo, res->old_fattr->time_start);
- if (new_dir != old_dir)
- update_changeattr(new_dir, &res->new_cinfo, res->new_fattr->time_start);
+ if (new_dir != old_dir) {
+ /* Note: If we moved a directory, nlink will change */
+ update_changeattr(old_dir, &res->old_cinfo,
+ res->old_fattr->time_start,
+ NFS_INO_INVALID_OTHER);
+ update_changeattr(new_dir, &res->new_cinfo,
+ res->new_fattr->time_start,
+ NFS_INO_INVALID_OTHER);
+ } else
+ update_changeattr(old_dir, &res->old_cinfo,
+ res->old_fattr->time_start,
+ 0);
}
return 1;
}
@@ -4446,7 +4457,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, const struct
status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
if (!status) {
- update_changeattr(dir, &res.cinfo, res.fattr->time_start);
+ update_changeattr(dir, &res.cinfo, res.fattr->time_start, 0);
status = nfs_post_op_update_inode(inode, res.fattr);
if (!status)
nfs_setsecurity(inode, res.fattr, res.label);
@@ -4523,7 +4534,7 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_
if (status == 0) {
spin_lock(&dir->i_lock);
update_changeattr_locked(dir, &data->res.dir_cinfo,
- data->res.fattr->time_start);
+ data->res.fattr->time_start, 0);
/* Creating a directory bumps nlink in the parent */
if (data->arg.ftype == NF4DIR)
nfs4_inc_nlink_locked(dir);
--
2.17.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 3/3] NFSv4: Mark the inode change attribute up to date in update_changeattr()
2018-07-31 17:24 ` [PATCH v2 2/3] NFSv4: Detect nlink changes on cross-directory renames too Trond Myklebust
@ 2018-07-31 17:24 ` Trond Myklebust
0 siblings, 0 replies; 4+ messages in thread
From: Trond Myklebust @ 2018-07-31 17:24 UTC (permalink / raw)
To: Anna Schumaker; +Cc: linux-nfs
When we update the change attribute, we should also clear the flag that
says it is out of date.
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
---
fs/nfs/nfs4proc.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 9d181d76c744..a1faeb2de954 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1107,6 +1107,7 @@ update_changeattr_locked(struct inode *dir, struct nfs4_change_info *cinfo,
inode_set_iversion_raw(dir, cinfo->after);
nfsi->read_cache_jiffies = timestamp;
nfsi->attr_gencount = nfs_inc_attr_generation_counter();
+ nfsi->cache_validity &= ~NFS_INO_INVALID_CHANGE;
nfs_fscache_invalidate(dir);
}
--
2.17.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2018-07-31 19:06 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-31 17:24 [PATCH v2 0/3] Fix mkdir/rmdir() in NFSv4 Trond Myklebust
2018-07-31 17:24 ` [PATCH v2 1/3] NFSv4: bump/drop the nlink count on the parent dir when we mkdir/rmdir Trond Myklebust
2018-07-31 17:24 ` [PATCH v2 2/3] NFSv4: Detect nlink changes on cross-directory renames too Trond Myklebust
2018-07-31 17:24 ` [PATCH v2 3/3] NFSv4: Mark the inode change attribute up to date in update_changeattr() Trond Myklebust
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.