diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c index 8061169c3..9803c7fec 100644 --- a/module/os/linux/zfs/zfs_vnops_os.c +++ b/module/os/linux/zfs/zfs_vnops_os.c @@ -1789,24 +1789,36 @@ zfs_setattr_dir(znode_t *dzp) &gid, sizeof (gid)); } - if (zp->z_projid != dzp->z_projid) { + + uint64_t projid = dzp->z_projid; + if (zp->z_projid != projid) { if (!(zp->z_pflags & ZFS_PROJID)) { - zp->z_pflags |= ZFS_PROJID; - SA_ADD_BULK_ATTR(bulk, count, - SA_ZPL_FLAGS(zfsvfs), NULL, &zp->z_pflags, - sizeof (zp->z_pflags)); + err = sa_add_projid(zp->z_sa_hdl, tx, projid); + if (unlikely(err == EEXIST)) { + err = 0; + } else if (err != 0) { + goto sa_add_projid_err; + } else { + projid = ZFS_INVALID_PROJID; + } } - zp->z_projid = dzp->z_projid; - SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_PROJID(zfsvfs), - NULL, &zp->z_projid, sizeof (zp->z_projid)); + if (projid != ZFS_INVALID_PROJID) { + zp->z_projid = projid; + SA_ADD_BULK_ATTR(bulk, count, + SA_ZPL_PROJID(zfsvfs), NULL, &zp->z_projid, + sizeof (zp->z_projid)); + } } +sa_add_projid_err: mutex_exit(&dzp->z_lock); if (likely(count > 0)) { err = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx); dmu_tx_commit(tx); + } else if (projid == ZFS_INVALID_PROJID) { + dmu_tx_commit(tx); } else { dmu_tx_abort(tx); } diff --git a/tests/zfs-tests/tests/functional/upgrade/upgrade_projectquota_001_pos.ksh b/tests/zfs-tests/tests/functional/upgrade/upgrade_projectquota_001_pos.ksh index 2ad37e06a..2c365e37a 100755 --- a/tests/zfs-tests/tests/functional/upgrade/upgrade_projectquota_001_pos.ksh +++ b/tests/zfs-tests/tests/functional/upgrade/upgrade_projectquota_001_pos.ksh @@ -63,6 +63,7 @@ log_must mkfiles $TESTDIR/fs2/tf $((RANDOM % 100 + 1)) log_must zfs create $TESTPOOL/fs3 log_must mkdir $TESTDIR/fs3/dir log_must mkfiles $TESTDIR/fs3/tf $((RANDOM % 100 + 1)) +log_must set_xattr_stdin passwd $TESTDIR/fs3/dir < /etc/passwd # Make sure project quota is disabled zfs projectspace -o used $TESTPOOL | grep -q "USED" && @@ -109,9 +110,23 @@ log_must chattr -p 100 $TESTDIR/fs3/dir log_must sleep 5 # upgrade done in the background so let's wait for a while zfs projectspace -o used $TESTPOOL/fs3 | grep -q "USED" || log_fail "project quota should be enabled for $TESTPOOL/fs3" +dirino=$(stat -c '%i' $TESTDIR/fs3/dir) +log_must zdb -ddddd $TESTPOOL/fs3 $dirino +xattrdirino=$(zdb -ddddd $TESTPOOL/fs3 $dirino |grep -w "xattr" |awk '{print $2}') +echo "xattrdirino: $xattrdirino" +expectedcnt=1 +echo "expectedcnt: $expectedcnt" +if [ "$xattrdirino" != "" ]; then + expectedcnt=$(($expectedcnt + 1)) + echo "expectedcnt: $expectedcnt" + log_must zdb -ddddd $TESTPOOL/fs3 $xattrdirino + xattrinocnt=$(zdb -ddddd $TESTPOOL/fs3 $xattrdirino |grep -w "(type:" |wc -l) + echo "xattrinocnt: $xattrinocnt" + expectedcnt=$(($expectedcnt + $xattrinocnt)) + echo "expectedcnt: $expectedcnt" +fi cnt=$(get_prop projectobjused@100 $TESTPOOL/fs3) -# if 'xattr=on', then 'cnt = 2' -[[ $cnt -ne 1 ]] && [[ $cnt -ne 2 ]] && +[[ $cnt -ne $expectedcnt ]] && log_fail "projectquota accounting failed $cnt" # All in all, after having been through this, the dataset for testpool