Calling fallocate() on a newly created file did not account quota
usage properly because the OST object did not have a UID/GID
assigned yet. Update the fallocate code in the OSC to always send
the file UID/GID/PROJID to the OST so that the object ownership
can be updated before space is allocated.
Test-case: sanity-quota/78 added
Fixes:
48457868a02a ("LU-3606 fallocate: Implement fallocate preallocate operation")
Signed-off-by: Arshad Hussain <arshad.hussain@aeoncomputing.com>
Change-Id: I86d80a7f415a80100f7d2fb5f417cf47bf5b2900
Reviewed-on: https://review.whamcloud.com/45475
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Bobi Jam <bobijam@hotmail.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
int sa_falloc_mode;
loff_t sa_falloc_offset;
loff_t sa_falloc_end;
+ uid_t sa_falloc_uid;
+ gid_t sa_falloc_gid;
} ci_setattr;
struct cl_data_version_io {
u64 dv_data_version;
io->u.ci_setattr.sa_falloc_offset = offset;
io->u.ci_setattr.sa_falloc_end = offset + len;
io->u.ci_setattr.sa_subtype = CL_SETATTR_FALLOCATE;
+
+ CDEBUG(D_INODE, "UID %u GID %u\n",
+ from_kuid(&init_user_ns, inode->i_uid),
+ from_kgid(&init_user_ns, inode->i_gid));
+
+ io->u.ci_setattr.sa_falloc_uid = from_kuid(&init_user_ns, inode->i_uid);
+ io->u.ci_setattr.sa_falloc_gid = from_kgid(&init_user_ns, inode->i_gid);
+
if (io->u.ci_setattr.sa_falloc_end > size) {
loff_t newsize = io->u.ci_setattr.sa_falloc_end;
if (cl_io_is_fallocate(io)) {
io->u.ci_setattr.sa_falloc_offset = start;
io->u.ci_setattr.sa_falloc_end = end;
+ io->u.ci_setattr.sa_falloc_uid =
+ parent->u.ci_setattr.sa_falloc_uid;
+ io->u.ci_setattr.sa_falloc_gid =
+ parent->u.ci_setattr.sa_falloc_gid;
}
if (cl_io_is_trunc(io)) {
loff_t new_size = parent->u.ci_setattr.sa_attr.lvb_size;
struct ldlm_resource *res;
struct ofd_object *fo;
__u64 flags = 0;
+ __u64 valid;
struct lustre_handle lh = { 0, };
int rc, mode;
__u64 start, end;
if (IS_ERR(fo))
GOTO(out, rc = PTR_ERR(fo));
- la_from_obdo(&info->fti_attr, oa,
- OBD_MD_FLMTIME | OBD_MD_FLATIME | OBD_MD_FLCTIME);
+ valid = OBD_MD_FLUID | OBD_MD_FLGID | OBD_MD_FLPROJID |
+ OBD_MD_FLATIME | OBD_MD_FLMTIME | OBD_MD_FLCTIME;
+ la_from_obdo(&info->fti_attr, oa, valid);
rc = ofd_object_fallocate(tsi->tsi_env, fo, start, end, mode,
&info->fti_attr, oa);
rc = ofd_attr_get(tsi->tsi_env, fo, &info->fti_attr);
if (rc == 0)
- obdo_from_la(&repbody->oa, &info->fti_attr,
- OFD_VALID_FLAGS);
+ obdo_from_la(&repbody->oa, &info->fti_attr, OFD_VALID_FLAGS);
else
rc = 0;
oa->o_size = io->u.ci_setattr.sa_falloc_offset;
oa->o_blocks = io->u.ci_setattr.sa_falloc_end;
- oa->o_valid |= OBD_MD_FLSIZE | OBD_MD_FLBLOCKS;
+ oa->o_uid = io->u.ci_setattr.sa_falloc_uid;
+ oa->o_gid = io->u.ci_setattr.sa_falloc_gid;
+ oa->o_valid |= OBD_MD_FLSIZE | OBD_MD_FLBLOCKS |
+ OBD_MD_FLUID | OBD_MD_FLGID;
+
+ CDEBUG(D_INODE, "size %llu blocks %llu uid %u gid %u\n",
+ oa->o_size, oa->o_blocks, oa->o_uid, oa->o_gid);
result = osc_fallocate_base(osc_export(cl2osc(obj)),
oa, osc_async_upcall,
cbargs, falloc_mode);
}
run_test 77 "lfs setquota should fail in Lustre mount with 'ro'"
+test_78()
+{
+ (( $OST1_VERSION >= $(version_code 2.14.55) )) ||
+ skip "need OST at least 2.14.55"
+ check_set_fallocate_or_skip
+
+ setup_quota_test || error "setup quota failed with $?"
+ stack_trap cleanup_quota_test
+
+ # enable ost quota
+ set_ost_qtype $QTYPE || error "enable ost quota failed"
+
+ mkdir -p $DIR/$tdir || error "failed to create $tdir"
+ chown $TSTUSR $DIR/$tdir || error "failed to chown $tdir"
+
+ # setup quota limit
+ $LFS setquota -u $TSTUSR -b25M -B25M $DIR/$tdir ||
+ error "lfs setquota failed"
+
+ # call fallocate
+ runas -u $TSTUSR -g $TSTUSR fallocate -l 204800 $DIR/$tdir/$tfile
+
+ kbytes=$(lfs quota -u $TSTUSR $DIR |
+ awk -v pattern=$DIR 'match($0, pattern) {printf $2}')
+ echo "kbytes returned:$kbytes"
+
+ # For file size of 204800. We should be having roughly 200 kbytes
+ # returned. Anything alarmingly low (50 taken as arbitrary value)
+ # would bail out this TC. Also this also avoids $kbytes of 0
+ # to be used in calculation below.
+ (( $kbytes > 50 )) ||
+ error "fallocate did not use quota. kbytes returned:$kbytes"
+
+ local expect_lo=$(($kbytes * 95 / 100)) # 5% below
+ local expect_hi=$(($kbytes * 105 / 100)) # 5% above
+
+ # Verify kbytes is 200 (204800/1024). With a permited 5% drift
+ (( $kbytes >= $expect_lo && $kbytes <= $expect_hi )) ||
+ error "fallocate did not use quota correctly"
+}
+run_test 78 "Check fallocate increase quota usage"
+
quota_fini()
{
do_nodes $(comma_list $(nodes_list)) \