Dear Neil,I've stripped the code more, which still triggers the bug for me. On Bookworm, to get the binary, simply:
$ sudo apt-get install golang $ go build . And then give it an nfs mountpoint, e.g.: $ ./ds /mnt/nfs Meanwhile, I will try your patch too. Regards, Richard 2024-05-24 01:31 időpontban NeilBrown ezt írta:
On Fri, 24 May 2024, Richard Kojedzinszky wrote:Dear devs, I am attaching a stripped down version of the little program which triggers the bug very quickly, in a few minutes in my test lab. It turned out that a single NFS mountpoint is enough. Just start theprogram giving it the NFS mount as first argument. It will chdir there,and do file operations, which will trigger a lockup in a few minutes.I couldn't get the go code to run. But then it is a long time since I played with go and I didn't try very hard. If you could provide simple instructions and a list of package dependencies that I need to install (on Debian), I can give it a try. Or you could try this patch. It might help, but I don't have highhopes. It adds some memory barriers and fixes a bug which would cause a problem if memory allocation failed (but memory allocation never fails).NeilBrown diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index ac505671efbd..5bcc0d14d519 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c@@ -1804,7 +1804,7 @@ __nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags,} else { /* Wait for unlink to complete */ wait_var_event(&dentry->d_fsdata, - dentry->d_fsdata != NFS_FSDATA_BLOCKED); + smp_load_acquire(&dentry->d_fsdata) != NFS_FSDATA_BLOCKED); parent = dget_parent(dentry); ret = reval(d_inode(parent), dentry, flags); dput(parent);@@ -2508,7 +2508,7 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry)spin_unlock(&dentry->d_lock); error = nfs_safe_remove(dentry); nfs_dentry_remove_handle_error(dir, dentry, error); - dentry->d_fsdata = NULL; + smp_store_release(&dentry->d_fsdata, NULL); wake_up_var(&dentry->d_fsdata); out: trace_nfs_unlink_exit(dir, dentry, error);@@ -2616,7 +2616,7 @@ nfs_unblock_rename(struct rpc_task *task, struct nfs_renamedata *data){ struct dentry *new_dentry = data->new_dentry; - new_dentry->d_fsdata = NULL; + smp_store_release(&new_dentry->d_fsdata, NULL); wake_up_var(&new_dentry->d_fsdata); }@@ -2717,6 +2717,10 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry, must_unblock ? nfs_unblock_rename : NULL); if (IS_ERR(task)) { + if (must_unlock) { + smp_store_release(&new_dentry->d_fsdata, NULL); + wake_up_var(&new_dentry->d_fsdata); + } error = PTR_ERR(task); goto out; }
Attachment:
ds.tar
Description: Unix tar archive