From: Andrew Perepechko Date: Sun, 31 Oct 2021 20:03:30 +0000 (+0300) Subject: LU-15171 osd-ldiskfs: xattr_sem locking is missing for dquot_transfer X-Git-Tag: 2.14.56~97 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=e6c7fcdaf40b130c39af2e3ee8b108c6e31a8ca8;ds=sidebyside LU-15171 osd-ldiskfs: xattr_sem locking is missing for dquot_transfer 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 HPE-bug-id: LUS-10549 Reviewed-on: https://review.whamcloud.com/45424 Reviewed-by: Alexander Zarochentsev Tested-by: jenkins Reviewed-by: Andreas Dilger Tested-by: Maloo Reviewed-by: Oleg Drokin --- diff --git a/lustre/autoconf/lustre-core.m4 b/lustre/autoconf/lustre-core.m4 index acfb007..66d5256 100644 --- a/lustre/autoconf/lustre-core.m4 +++ b/lustre/autoconf/lustre-core.m4 @@ -461,6 +461,21 @@ get_projid, [ ]) ]) # 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 +],[ + 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 # @@ -2568,6 +2583,7 @@ AC_DEFUN([LC_PROG_LINUX], [ # 4.13 LC_BIO_INTEGRITY_ENABLED + LC_HAVE_GET_INODE_USAGE # 4.14 LC_PAGEVEC_INIT_ONE_PARAM diff --git a/lustre/osd-ldiskfs/osd_handler.c b/lustre/osd-ldiskfs/osd_handler.c index 1b94f32..34f8465c 100644 --- a/lustre/osd-ldiskfs/osd_handler.c +++ b/lustre/osd-ldiskfs/osd_handler.c @@ -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]) { + lock_dquot_transfer(inode); err = __dquot_transfer(inode, transfer_to); + unlock_dquot_transfer(inode); 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); + lock_dquot_transfer(inode); 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); diff --git a/lustre/osd-ldiskfs/osd_internal.h b/lustre/osd-ldiskfs/osd_internal.h index 3c47beb..705d8b0 100644 --- a/lustre/osd-ldiskfs/osd_internal.h +++ b/lustre/osd-ldiskfs/osd_internal.h @@ -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 */ +#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 */