ceph: check the cephx mds auth access for setattr
authorXiubo Li <xiubli@redhat.com>
Wed, 8 Nov 2023 02:54:17 +0000 (10:54 +0800)
committerIlya Dryomov <idryomov@gmail.com>
Thu, 23 May 2024 08:35:47 +0000 (10:35 +0200)
If we hit any failre just try to force it to do the sync setattr.

Link: https://tracker.ceph.com/issues/61333
Signed-off-by: Xiubo Li <xiubli@redhat.com>
Reviewed-by: Milind Changire <mchangir@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
fs/ceph/inode.c

index 7b2e77517f235ecd47264061c04bae2e6d0b7c83..3f1f048d920659a8f1646006f23ec8b9081b52ad 100644 (file)
@@ -2480,6 +2480,34 @@ int __ceph_setattr(struct mnt_idmap *idmap, struct inode *inode,
        bool lock_snap_rwsem = false;
        bool fill_fscrypt;
        int truncate_retry = 20; /* The RMW will take around 50ms */
+       struct dentry *dentry;
+       char *path;
+       int pathlen;
+       u64 pathbase;
+       bool do_sync = false;
+
+       dentry = d_find_alias(inode);
+       if (!dentry) {
+               do_sync = true;
+       } else {
+               path = ceph_mdsc_build_path(mdsc, dentry, &pathlen, &pathbase, 0);
+               if (IS_ERR(path)) {
+                       do_sync = true;
+                       err = 0;
+               } else {
+                       err = ceph_mds_check_access(mdsc, path, MAY_WRITE);
+               }
+               ceph_mdsc_free_path(path, pathlen);
+               dput(dentry);
+
+               /* For none EACCES cases will let the MDS do the mds auth check */
+               if (err == -EACCES) {
+                       return err;
+               } else if (err < 0) {
+                       do_sync = true;
+                       err = 0;
+               }
+       }
 
 retry:
        prealloc_cf = ceph_alloc_cap_flush();
@@ -2526,7 +2554,7 @@ retry:
                /* It should never be re-set once set */
                WARN_ON_ONCE(ci->fscrypt_auth);
 
-               if (issued & CEPH_CAP_AUTH_EXCL) {
+               if (!do_sync && (issued & CEPH_CAP_AUTH_EXCL)) {
                        dirtied |= CEPH_CAP_AUTH_EXCL;
                        kfree(ci->fscrypt_auth);
                        ci->fscrypt_auth = (u8 *)cia->fscrypt_auth;
@@ -2555,7 +2583,7 @@ retry:
                      ceph_vinop(inode),
                      from_kuid(&init_user_ns, inode->i_uid),
                      from_kuid(&init_user_ns, attr->ia_uid));
-               if (issued & CEPH_CAP_AUTH_EXCL) {
+               if (!do_sync && (issued & CEPH_CAP_AUTH_EXCL)) {
                        inode->i_uid = fsuid;
                        dirtied |= CEPH_CAP_AUTH_EXCL;
                } else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 ||
@@ -2573,7 +2601,7 @@ retry:
                      ceph_vinop(inode),
                      from_kgid(&init_user_ns, inode->i_gid),
                      from_kgid(&init_user_ns, attr->ia_gid));
-               if (issued & CEPH_CAP_AUTH_EXCL) {
+               if (!do_sync && (issued & CEPH_CAP_AUTH_EXCL)) {
                        inode->i_gid = fsgid;
                        dirtied |= CEPH_CAP_AUTH_EXCL;
                } else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 ||
@@ -2587,7 +2615,7 @@ retry:
        if (ia_valid & ATTR_MODE) {
                doutc(cl, "%p %llx.%llx mode 0%o -> 0%o\n", inode,
                      ceph_vinop(inode), inode->i_mode, attr->ia_mode);
-               if (issued & CEPH_CAP_AUTH_EXCL) {
+               if (!do_sync && (issued & CEPH_CAP_AUTH_EXCL)) {
                        inode->i_mode = attr->ia_mode;
                        dirtied |= CEPH_CAP_AUTH_EXCL;
                } else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 ||
@@ -2606,11 +2634,11 @@ retry:
                      inode, ceph_vinop(inode),
                      atime.tv_sec, atime.tv_nsec,
                      attr->ia_atime.tv_sec, attr->ia_atime.tv_nsec);
-               if (issued & CEPH_CAP_FILE_EXCL) {
+               if (!do_sync && (issued & CEPH_CAP_FILE_EXCL)) {
                        ci->i_time_warp_seq++;
                        inode_set_atime_to_ts(inode, attr->ia_atime);
                        dirtied |= CEPH_CAP_FILE_EXCL;
-               } else if ((issued & CEPH_CAP_FILE_WR) &&
+               } else if (!do_sync && (issued & CEPH_CAP_FILE_WR) &&
                           timespec64_compare(&atime,
                                              &attr->ia_atime) < 0) {
                        inode_set_atime_to_ts(inode, attr->ia_atime);
@@ -2646,7 +2674,7 @@ retry:
                                                     CEPH_FSCRYPT_BLOCK_SIZE));
                        req->r_fscrypt_file = attr->ia_size;
                        fill_fscrypt = true;
-               } else if ((issued & CEPH_CAP_FILE_EXCL) && attr->ia_size >= isize) {
+               } else if (!do_sync && (issued & CEPH_CAP_FILE_EXCL) && attr->ia_size >= isize) {
                        if (attr->ia_size > isize) {
                                i_size_write(inode, attr->ia_size);
                                inode->i_blocks = calc_inode_blocks(attr->ia_size);
@@ -2683,11 +2711,11 @@ retry:
                      inode, ceph_vinop(inode),
                      mtime.tv_sec, mtime.tv_nsec,
                      attr->ia_mtime.tv_sec, attr->ia_mtime.tv_nsec);
-               if (issued & CEPH_CAP_FILE_EXCL) {
+               if (!do_sync && (issued & CEPH_CAP_FILE_EXCL)) {
                        ci->i_time_warp_seq++;
                        inode_set_mtime_to_ts(inode, attr->ia_mtime);
                        dirtied |= CEPH_CAP_FILE_EXCL;
-               } else if ((issued & CEPH_CAP_FILE_WR) &&
+               } else if (!do_sync && (issued & CEPH_CAP_FILE_WR) &&
                           timespec64_compare(&mtime, &attr->ia_mtime) < 0) {
                        inode_set_mtime_to_ts(inode, attr->ia_mtime);
                        dirtied |= CEPH_CAP_FILE_WR;