The error:
executing tar command, stopping after 5 occurrences of error
tar: nfs-test/pkgs/libxml2-2.9.10-h72842e0_3/share/aclocal/libxml.m4: Cannot hard link to ‘nfs-test/share/aclocal/libxml.m4’: Read-only file system
tar: nfs-test/pkgs/libxml2-2.9.10-h72842e0_3/share/gtk-doc/html/libxml2/libxml2-list.html: Cannot hard link to ‘nfs-test/share/gtk-doc/html/libxml2/libxml2-list.html’: Read-only file system
tar: nfs-test/pkgs/libxml2-2.9.10-h72842e0_3/share/gtk-doc/html/libxml2/libxml2-dict.html: Cannot hard link to ‘nfs-test/share/gtk-doc/html/libxml2/libxml2-dict.html’: Read-only file system
tar: nfs-test/pkgs/libxml2-2.9.10-h72842e0_3/share/gtk-doc/html/libxml2/libxml2-valid.html: Cannot hard link to ‘nfs-test/share/gtk-doc/html/libxml2/libxml2-valid.html’: Read-only file system
tar: nfs-test/pkgs/libxml2-2.9.10-h72842e0_3/share/gtk-doc/html/libxml2/libxml2-parser.html: Cannot hard link to ‘nfs-test/share/gtk-doc/html/libxml2/libxml2-parser.html’: Read-only file system
Added on debug log in ceph_link():
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index c28de23e12a1..4c9e84c6ba35 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -1151,8 +1151,10 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir,
if (err)
return err;
- dout("link in dir %p old_dentry %p dentry %p\n", dir,
- old_dentry, dentry);
+ dout("link in dir %p old_dentry %p:%pd disconnect=%d old_dentry's parent %p:%pd parent ino %llx.%llx, dentry %p:%pd disconnect=%d dentry's parent %p:%pd, parent ino %llx.%llx\n", dir,
+ old_dentry, old_dentry, (old_dentry->d_flags & DCACHE_DISCONNECTED), old_dentry->d_parent, old_dentry->d_parent, ceph_vinop(d_inode(old_dentry->d_parent)),
+ dentry, dentry, dentry->d_flags & DCACHE_DISCONNECTED, dentry->d_parent, dentry->d_parent, ceph_vinop(d_inode(dentry->d_parent)));
+
req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LINK, USE_AUTH_MDS);
if (IS_ERR(req)) {
d_drop(dentry);
And tried to reproduce it again, the logs:
<7>[331620.275135] ceph: link in dir 000000002d467779 old_dentry 000000001a6a54e7:/ disconnect=32 old_dentry's parent 000000001a6a54e7:/ parent ino 100007bb6d8.fffffffffffffffe, dentry 00000000041642b2:libxml.m4 disconnect=0 dentry's parent 00000000567fb787:aclocal, parent ino 100007cf5c6.fffffffffffffffe
<7>[331620.275140] ceph: do_request on 000000009aca5048
<7>[331620.275141] ceph: submit_request on 000000009aca5048 for inode 000000002d467779
<7>[331620.275143] ceph: __register_request 000000009aca5048 tid 347271
<7>[331620.275145] ceph: __choose_mds 000000002d467779 is_hash=1 (0xff728fe9) mode 2
<7>[331620.275147] ceph: __choose_mds 000000002d467779 100007cf5c6.fffffffffffffffe mds0 (auth cap 00000000f9161ca8)
<7>[331620.275150] ceph: do_request mds0 session 0000000000fba58e state open
<7>[331620.275151] ceph: __prepare_send_request 000000009aca5048 tid 347271 link (attempt 1)
<7>[331620.275153] ceph: dentry 00000000041642b2 100007cf5c6/libxml.m4
<7>[331620.275154] ceph: dentry 000000001a6a54e7 100007bb6d8//
<7>[331620.275157] ceph: r_parent = 000000002d467779
<7>[331620.275159] ceph: do_request waiting
<7>[331620.275774] ceph: handle_reply 000000009aca5048
<7>[331620.275777] ceph: __unregister_request 000000009aca5048 tid 347271
<7>[331620.275778] ceph: handle_reply tid 347271 result -30
<7>[331620.275785] ceph: do_request waited, got 0
<7>[331620.275786] ceph: do_request 000000009aca5048 done, result -30
The uplayer just passed a invalidate dentry: old_dentry 000000001a6a54e7:/ disconnect=32 old_dentry's parent 000000001a6a54e7:/ parent ino 100007bb6d8.fffffffffffffffe. The dentry is DCACHE_DISCONNECTED and the name is /* and the *ino# is 100007bb6d8. And then parsed it as a snapdir 100007bb6d8// and passed it to MDS.
While from the MDS side logs, the snapdir is not permitted to be modified and then just returned as -EROFS:
2023-04-24T06:55:31.337+0200 7f0c1a0d1700 7 mds.0.server dispatch_client_request client_request(client.194038:347271 link #0x100007cf5c6/libxml.m4 #0x100007bb6d8// 2023-04-24T06:55:31.337532+0200 caller_uid=2000, caller_gid=2000{10,2000,}) v6
2023-04-24T06:55:31.337+0200 7f0c1a0d1700 7 mds.0.server handle_client_link #0x100007cf5c6/libxml.m4 to #0x100007bb6d8//
2023-04-24T06:55:31.337+0200 7f0c1a0d1700 10 mds.0.server rdlock_two_paths_xlock_destdn request(client.194038:347271 nref=2 cr=0x55fe5a5ac280) #0x100007cf5c6/libxml.m4 #0x100007bb6d8//
2023-04-24T06:55:31.337+0200 7f0c1a0d1700 7 mds.0.server reply_client_request -30 ((30) Read-only file system) client_request(client.194038:347271 link #0x100007cf5c6/libxml.m4 #0x100007bb6d8// 2023-04-24T06:55:31.337532+0200 caller_uid=2000, caller_gid=2000{10,2000,}) v6
2023-04-24T06:55:31.337+0200 7f0c1a0d1700 10 mds.0.server apply_allocated_inos 0x0 / [] / 0x0
2023-04-24T06:55:31.337+0200 7f0c1a0d1700 20 mds.0.server lat 0.000268
2023-04-24T06:55:31.337+0200 7f0c1a0d1700 10 mds.0.1473 send_message_client client.194038 v1:10.41.24.225:0/723549921 client_reply(???:347271 = -30 (30) Read-only file system safe) v1
2023-04-24T06:55:31.337+0200 7f0c1a0d1700 1 -- [v2:10.41.24.14:6806/2297598453,v1:10.41.24.14:6813/2297598453] --> v1:10.41.24.225:0/723549921 -- client_reply(???:347271 = -30 (30) Read-only file system safe) v1 -- 0x55fde61b5c00 con 0x5601bdfdc800
But the old dentry's parent inode is 100007bb6d8, which is /data/nfs/nfs-test/share/aclocal/libxml.m4:
2023-04-24T06:55:31.337+0200 7f0c1a0d1700 7 mds.0.locker rdlock_finish on (ixattr sync) on [inode 0x100007bb6d8 [...7b,head] /data/nfs/nfs-test/share/aclocal/libxml.m4 auth v6 ap=1 snaprealm=0x56014fb6a780 s=7881 nl=2 n(v0 rc2023-04-24T06:43:58.786177+0200 b7881 1=1+0) (iversion lock) caps={194038=pAsLsXsFscr/-@2} | ptrwaiter=0 request=0 lock=0 caps=1 remoteparent=1 dirtyparent=0 dirty=0 authpin=1 0x5601c9706800]
This is incorrect, because that means the kclient passed a dentry, which is libxml.m4// and the libxml.m4 is a directory.