Whamcloud - gitweb
LU-15171 osd-ldiskfs: xattr_sem locking is missing for dquot_transfer 24/45424/6
authorAndrew Perepechko <andrew.perepechko@hpe.com>
Sun, 31 Oct 2021 20:03:30 +0000 (23:03 +0300)
committerOleg Drokin <green@whamcloud.com>
Sat, 20 Nov 2021 06:24:43 +0000 (06:24 +0000)
Kernel commit 7a9ca53ae (~v4.13) added the requirement for xattr_sem locking
when calling *dquot_transfer. As of now, in rare cases, it is possible that
we can modify inode xattrs and perform their consistency checks in parallel,
which can fail.

Change-Id: I041694e30ce6c8398864c0ad57671df0bffd2f52
Signed-off-by: Andrew Perepechko <andrew.perepechko@hpe.com>
HPE-bug-id: LUS-10549
Reviewed-on: https://review.whamcloud.com/45424
Reviewed-by: Alexander Zarochentsev <alexander.zarochentsev@hpe.com>
Tested-by: jenkins <devops@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/autoconf/lustre-core.m4
lustre/osd-ldiskfs/osd_handler.c
lustre/osd-ldiskfs/osd_internal.h

index acfb007..66d5256 100644 (file)
@@ -461,6 +461,21 @@ get_projid, [
 ])
 ]) # LC_HAVE_PROJECT_QUOTA
 
 ])
 ]) # LC_HAVE_PROJECT_QUOTA
 
+AC_DEFUN([LC_HAVE_GET_INODE_USAGE], [
+LB_CHECK_COMPILE([if get_inode_usage exists],
+get_inode_usage, [
+       struct inode;
+       #include <linux/quota.h>
+],[
+       struct dquot_operations ops = { };
+
+       ops.get_inode_usage(NULL, NULL);
+],[
+       AC_DEFINE(HAVE_GET_INODE_USAGE, 1,
+               [get_inode_usage function exists])
+])
+]) # LC_HAVE_GET_INODE_USAGE
+
 #
 # LC_INVALIDATE_RANGE
 #
 #
 # LC_INVALIDATE_RANGE
 #
@@ -2568,6 +2583,7 @@ AC_DEFUN([LC_PROG_LINUX], [
 
        # 4.13
        LC_BIO_INTEGRITY_ENABLED
 
        # 4.13
        LC_BIO_INTEGRITY_ENABLED
+       LC_HAVE_GET_INODE_USAGE
 
        # 4.14
        LC_PAGEVEC_INIT_ONE_PARAM
 
        # 4.14
        LC_PAGEVEC_INIT_ONE_PARAM
index 1b94f32..34f8465 100644 (file)
@@ -3062,7 +3062,9 @@ static int osd_transfer_project(struct inode *inode, __u32 projid,
        dquot_initialize(inode);
        transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid));
        if (transfer_to[PRJQUOTA]) {
        dquot_initialize(inode);
        transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid));
        if (transfer_to[PRJQUOTA]) {
+               lock_dquot_transfer(inode);
                err = __dquot_transfer(inode, transfer_to);
                err = __dquot_transfer(inode, transfer_to);
+               unlock_dquot_transfer(inode);
                dqput(transfer_to[PRJQUOTA]);
                if (err)
                        return err;
                dqput(transfer_to[PRJQUOTA]);
                if (err)
                        return err;
@@ -3095,7 +3097,9 @@ static int osd_quota_transfer(struct inode *inode, const struct lu_attr *attr,
                iattr.ia_uid = make_kuid(&init_user_ns, attr->la_uid);
                iattr.ia_gid = make_kgid(&init_user_ns, attr->la_gid);
 
                iattr.ia_uid = make_kuid(&init_user_ns, attr->la_uid);
                iattr.ia_gid = make_kgid(&init_user_ns, attr->la_gid);
 
+               lock_dquot_transfer(inode);
                rc = dquot_transfer(inode, &iattr);
                rc = dquot_transfer(inode, &iattr);
+               unlock_dquot_transfer(inode);
                if (rc) {
                        CERROR("%s: quota transfer failed. Is quota enforcement enabled on the ldiskfs filesystem? rc = %d\n",
                               osd_ino2name(inode), rc);
                if (rc) {
                        CERROR("%s: quota transfer failed. Is quota enforcement enabled on the ldiskfs filesystem? rc = %d\n",
                               osd_ino2name(inode), rc);
index 3c47beb..705d8b0 100644 (file)
@@ -1641,4 +1641,12 @@ static inline bool bio_integrity_prep_fn(struct bio *bio,
 #define osd_bio_nr_segs(bio)           bio_segments((bio))
 #endif /* HAVE_BIO_BI_PHYS_SEGMENTS */
 
 #define osd_bio_nr_segs(bio)           bio_segments((bio))
 #endif /* HAVE_BIO_BI_PHYS_SEGMENTS */
 
+#ifdef HAVE_GET_INODE_USAGE
+#define lock_dquot_transfer(inode) down_read(&LDISKFS_I(inode)->xattr_sem)
+#define unlock_dquot_transfer(inode) up_read(&LDISKFS_I(inode)->xattr_sem)
+#else
+#define lock_dquot_transfer(inode) do {} while (0)
+#define unlock_dquot_transfer(inode) do {} while (0)
+#endif
+
 #endif /* _OSD_INTERNAL_H */
 #endif /* _OSD_INTERNAL_H */