From fa2e46bb3f6d88e2493d55203a215bb81701fa10 Mon Sep 17 00:00:00 2001 From: anserper Date: Sun, 6 Jul 2008 17:37:12 +0000 Subject: [PATCH] Branch b1_8 b=13904 i=Johann Lombardi(johann) i=ZhiYong Tian(tianzy) Adding 64-bit quota file support --- lustre/autoconf/lustre-core.m4 | 25 ++++ lustre/doc/lfs.1 | 6 +- lustre/include/lustre/lustre_idl.h | 7 +- lustre/include/lustre/lustre_user.h | 5 +- lustre/include/lustre_quota.h | 13 +- lustre/include/obd.h | 1 + lustre/llite/dir.c | 1 + lustre/lvfs/fsfilt_ext3.c | 121 +++++++++++++--- lustre/lvfs/lustre_quota_fmt.h | 5 +- lustre/lvfs/lustre_quota_fmt_convert.c | 92 +++++++++++- lustre/quota/quota_check.c | 1 + lustre/quota/quota_context.c | 3 +- lustre/quota/quota_ctl.c | 24 +++- lustre/quota/quota_interface.c | 253 ++++++++++++++++++++++----------- lustre/quota/quota_internal.h | 1 + lustre/quota/quota_master.c | 34 ++++- lustre/quota/quotactl_test.c | 2 +- lustre/tests/sanity-quota.sh | 80 +++++++++-- lustre/utils/lfs.c | 8 +- lustre/utils/lustre_cfg.c | 4 +- 20 files changed, 539 insertions(+), 147 deletions(-) diff --git a/lustre/autoconf/lustre-core.m4 b/lustre/autoconf/lustre-core.m4 index 97edc50..2792f61 100644 --- a/lustre/autoconf/lustre-core.m4 +++ b/lustre/autoconf/lustre-core.m4 @@ -1307,6 +1307,7 @@ AC_DEFUN([LC_PROG_LINUX], LC_QUOTA_READ LC_COOKIE_FOLLOW_LINK LC_FUNC_RCU + LC_QUOTA64 # does the kernel have VFS intent patches? LC_VFS_INTENT_PATCHES @@ -1533,6 +1534,30 @@ LB_LINUX_TRY_COMPILE([ ]) # +# LC_QUOTA64 +# linux kernel may have 64-bit limits support +# +AC_DEFUN([LC_QUOTA64], +[AC_MSG_CHECKING([if kernel has 64-bit quota limits support]) +LB_LINUX_TRY_COMPILE([ + #include + #include + #include + int versions[] = V2_INITQVERSIONS_R1; + struct v2_disk_dqblk_r1 dqblk_r1; +],[],[ + AC_DEFINE(HAVE_QUOTA64, 1, [have quota64]) + AC_MSG_RESULT([yes]) + +],[ + AC_MSG_WARN([You have got no 64-bit kernel quota support.]) + AC_MSG_WARN([Continuing with limited quota support.]) + AC_MSG_WARN([quotacheck is needed for filesystems with recent quota versions.]) + AC_MSG_RESULT([no]) +]) +]) + +# # LC_CONFIGURE # # other configure checks diff --git a/lustre/doc/lfs.1 b/lustre/doc/lfs.1 index 3bc9186..d00fcac 100644 --- a/lustre/doc/lfs.1 +++ b/lustre/doc/lfs.1 @@ -33,7 +33,7 @@ lfs \- Lustre utility to create a file with specific striping pattern, find the .br .B lfs quotaoff [-ug] .br -.B lfs quotainv [-ug] +.B lfs quotainv [-ug] [-f] .br .B lfs setquota [-u|--user|-g|--group] \fB[--block-softlimit ] @@ -117,8 +117,8 @@ To turn filesystem quotas on. Options specify quota for users (-u) groups (-g) a .B quotaoff [-ugf] To turn filesystem quotas off. Options specify quota for users (-u) groups (-g) and force (-f) .TP -.B quotainv [-ug] -Clear quota files, all of their quota entries, for (-u) users or (-g) groups; after quotainv one must use quotacheck before using quotas. USE THIS COMMAND WITH EXTREME CARE, ITS RESULTS CANNOT BE UNDONE. +.B quotainv [-ug] [-f] +Clear quota files (administrative quota files if used without -f, operational quota files otherwise), all of their quota entries, for (-u) users or (-g) groups; after quotainv one must use quotacheck before using quotas. DO NOT USE THIS COMMAND UNLESS YOU REALLY KNOW WHAT IT DOES. IT IS MAINLY FOR INTERNAL PURPOSES. .TP .B setquota [-u|-g] [--block-softlimit ] [--block-hardlimit ] [--inode-softlimit ] [--inode-hardlimit ] To set filesystem quotas for users or groups. Limits can be specified with -b, -k, -m, -g, -t, -p suffixes which specify units of 1, 2^10, 2^20, 2^30, 2^40 and 2^50 accordingly. Block limits unit is kilobyte (1024) by default and block limits are always kilobyte-grained (even if specified in bytes), see EXAMPLES diff --git a/lustre/include/lustre/lustre_idl.h b/lustre/include/lustre/lustre_idl.h index 84fe7d7..dace6cc 100644 --- a/lustre/include/lustre/lustre_idl.h +++ b/lustre/include/lustre/lustre_idl.h @@ -759,9 +759,12 @@ extern void lustre_swab_mds_body (struct mds_body *b); #define Q_INITQUOTA 0x800101 /* init slave limits */ #define Q_GETOINFO 0x800102 /* get obd quota info */ #define Q_GETOQUOTA 0x800103 /* get obd quotas */ +#define Q_FINVALIDATE 0x800104 /* invalidate operational quotas */ -#define Q_TYPESET(oqc, type) \ - ((oqc)->qc_type == type || (oqc)->qc_type == UGQUOTA) +#define Q_TYPEMATCH(id, type) \ + ((id) == (type) || (id) == UGQUOTA) + +#define Q_TYPESET(oqc, type) Q_TYPEMATCH((oqc)->qc_type, type) #define Q_GETOCMD(oqc) \ ((oqc)->qc_cmd == Q_GETOINFO || (oqc)->qc_cmd == Q_GETOQUOTA) diff --git a/lustre/include/lustre/lustre_user.h b/lustre/include/lustre/lustre_user.h index 8a883e8..a87cf82 100644 --- a/lustre/include/lustre/lustre_user.h +++ b/lustre/include/lustre/lustre_user.h @@ -184,12 +184,11 @@ static inline char *obd_uuid2str(struct obd_uuid *uuid) #define LUSTRE_Q_GETQUOTA 0x800007 /* get user quota structure */ #define LUSTRE_Q_SETQUOTA 0x800008 /* set user quota structure */ /* lustre-specific control commands */ -#define LUSTRE_Q_INVALIDATE 0x80000b /* invalidate quota data */ +#define LUSTRE_Q_INVALIDATE 0x80000b /* invalidate quota data */ +#define LUSTRE_Q_FINVALIDATE 0x80000c /* invalidate filter quota data */ #define UGQUOTA 2 /* set both USRQUOTA and GRPQUOTA */ -#define QFMT_LDISKFS 2 /* QFMT_VFS_V0(2), quota format for ldiskfs */ - struct if_quotacheck { char obd_type[16]; struct obd_uuid obd_uuid; diff --git a/lustre/include/lustre_quota.h b/lustre/include/lustre_quota.h index eb8b227..a2d3635 100644 --- a/lustre/include/lustre_quota.h +++ b/lustre/include/lustre_quota.h @@ -148,14 +148,21 @@ static inline int lustre_quota_convert(struct lustre_quota_info *lqi, typedef int (*dqacq_handler_t) (struct obd_device * obd, struct qunit_data * qd, int opc); + +/* user quota is turned on on filter */ +#define LQC_USRQUOTA_FLAG (1 << 0) +/* group quota is turned on on filter */ +#define LQC_GRPQUOTA_FLAG (1 << 1) + +#define UGQUOTA2LQC(id) ((Q_TYPEMATCH(id, USRQUOTA) ? LQC_USRQUOTA_FLAG : 0) | \ + (Q_TYPEMATCH(id, GRPQUOTA) ? LQC_GRPQUOTA_FLAG : 0)) + struct lustre_quota_ctxt { struct super_block *lqc_sb; /* superblock this applies to */ struct obd_import *lqc_import; /* import used to send dqacq/dqrel RPC */ dqacq_handler_t lqc_handler; /* dqacq/dqrel RPC handler, only for quota master */ + unsigned long lqc_flags; /* quota flags */ unsigned long lqc_recovery:1, /* Doing recovery */ - lqc_atype:2, /* Turn on user/group quota at setup automatically, - * 0: none, 1: user quota, 2: group quota, 3: both */ - lqc_status:1, /* Quota status. 0:Off, 1:On */ lqc_switch_qs:1; /* the function of change qunit size * 0:Off, 1:On */ unsigned long lqc_iunit_sz; /* original unit size of file quota and diff --git a/lustre/include/obd.h b/lustre/include/obd.h index 7267fba..88a81a3 100644 --- a/lustre/include/obd.h +++ b/lustre/include/obd.h @@ -244,6 +244,7 @@ struct obd_device_target { struct super_block *obt_sb; atomic_t obt_quotachecking; struct lustre_quota_ctxt obt_qctxt; + lustre_quota_version_t obt_qfmt; }; typedef void (*obd_pin_extent_cb)(void *data); diff --git a/lustre/llite/dir.c b/lustre/llite/dir.c index 323bebd..ee9b255 100644 --- a/lustre/llite/dir.c +++ b/lustre/llite/dir.c @@ -938,6 +938,7 @@ static int ll_dir_ioctl(struct inode *inode, struct file *file, id = qctl->qc_id; switch (cmd) { case LUSTRE_Q_INVALIDATE: + case LUSTRE_Q_FINVALIDATE: case Q_QUOTAON: case Q_QUOTAOFF: case Q_SETQUOTA: diff --git a/lustre/lvfs/fsfilt_ext3.c b/lustre/lvfs/fsfilt_ext3.c index d0e1f88..88bf8dd 100644 --- a/lustre/lvfs/fsfilt_ext3.c +++ b/lustre/lvfs/fsfilt_ext3.c @@ -60,6 +60,8 @@ #include #endif +#include "lustre_quota_fmt.h" + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) #define FSFILT_DATA_TRANS_BLOCKS(sb) EXT3_DATA_TRANS_BLOCKS #define FSFILT_DELETE_TRANS_BLOCKS(sb) EXT3_DELETE_TRANS_BLOCKS @@ -1398,10 +1400,10 @@ static int fsfilt_ext3_setup(struct super_block *sb) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6)) && HAVE_QUOTA_SUPPORT /* enable journaled quota support */ /* kfreed in ext3_put_super() */ - sbi->s_qf_names[USRQUOTA] = kstrdup("lquota.user", GFP_KERNEL); + sbi->s_qf_names[USRQUOTA] = kstrdup("lquota.user.reserved", GFP_KERNEL); if (!sbi->s_qf_names[USRQUOTA]) return -ENOMEM; - sbi->s_qf_names[GRPQUOTA] = kstrdup("lquota.group", GFP_KERNEL); + sbi->s_qf_names[GRPQUOTA] = kstrdup("lquota.group.reserved", GFP_KERNEL); if (!sbi->s_qf_names[GRPQUOTA]) { kfree(sbi->s_qf_names[USRQUOTA]); sbi->s_qf_names[USRQUOTA] = NULL; @@ -1446,8 +1448,6 @@ static int fsfilt_ext3_get_op_len(int op, struct fsfilt_objinfo *fso, int logs) return 0; } -static const char *op_quotafile[] = { "lquota.user", "lquota.group" }; - #define DQINFO_COPY(out, in) \ do { \ Q_COPY(out, in, dqi_bgrace); \ @@ -1502,10 +1502,26 @@ static int fsfilt_ext3_quotactl(struct super_block *sb, continue; if (oqc->qc_cmd == Q_QUOTAON) { + lustre_quota_version_t qfmt = oqc->qc_id; + char *name[][MAXQUOTAS] = LUSTRE_OPQFILES_NAMES; + if (!qcop->quota_on) GOTO(out, rc = -ENOSYS); - rc = qcop->quota_on(sb, i, oqc->qc_id, - (char *)op_quotafile[i]); + + rc = qcop->quota_on(sb, i, QFMT_VFS_V0, + name[qfmt][i]); +#ifdef HAVE_QUOTA64 + if (rc == -ENOENT || rc == -EINVAL) { + /* see bug 13904 */ + rc = lustre_slave_quota_convert(qfmt, i); + if (!rc) + rc = qcop->quota_on(sb, i, + QFMT_VFS_V0, + name[qfmt][i]); + else if (rc == -ESTALE) + rc = -ENOENT; + } +#endif } else if (oqc->qc_cmd == Q_QUOTAOFF) { if (!qcop->quota_off) GOTO(out, rc = -ENOSYS); @@ -1546,8 +1562,29 @@ static int fsfilt_ext3_quotactl(struct super_block *sb, GOTO(out, rc = -ENOSYS); qcop->quota_sync(sb, oqc->qc_type); break; + case Q_FINVALIDATE: + CDEBUG(D_WARNING, "invalidating operational quota files\n"); + for (i = 0; i < MAXQUOTAS; i++) { + struct file *fp; + lustre_quota_version_t qfmt = oqc->qc_id; + char *name[][MAXQUOTAS] = LUSTRE_OPQFILES_NAMES; + + if (!Q_TYPESET(oqc, i)) + continue; + + fp = filp_open(name[qfmt][i], O_CREAT | O_TRUNC | O_RDWR, 0644); + if (IS_ERR(fp)) { + rc = PTR_ERR(fp); + CERROR("error invalidating operational quota file" + " %s (rc:%d)\n", name[qfmt][i], rc); + } else { + filp_close(fp, 0); + } + + } + break; default: - CERROR("unsupported quotactl command: %d", oqc->qc_cmd); + CERROR("unsupported quotactl command: %d\n", oqc->qc_cmd); LBUG(); } out: @@ -1653,7 +1690,7 @@ cqget(struct super_block *sb, struct hlist_head *hash, struct list_head *list, return cdqb; } -static inline int quota_onoff(struct super_block *sb, int cmd, int type) +static inline int quota_onoff(struct super_block *sb, int cmd, int type, int qfmt) { struct obd_quotactl *oqctl; int rc; @@ -1663,7 +1700,7 @@ static inline int quota_onoff(struct super_block *sb, int cmd, int type) RETURN(-ENOMEM); oqctl->qc_cmd = cmd; - oqctl->qc_id = QFMT_LDISKFS; + oqctl->qc_id = qfmt; oqctl->qc_type = type; rc = fsfilt_ext3_quotactl(sb, oqctl); @@ -1788,7 +1825,11 @@ static int add_inode_quota(struct inode *inode, struct qchk_ctxt *qctxt, static int v2_write_dqheader(struct file *f, int type) { static const __u32 quota_magics[] = V2_INITQMAGICS; +#ifdef HAVE_QUOTA64 + static const __u32 quota_versions[] = V2_INITQVERSIONS_R0; +#else static const __u32 quota_versions[] = V2_INITQVERSIONS; +#endif struct v2_disk_dqheader dqhead; loff_t offset = 0; @@ -1826,6 +1867,30 @@ static int v2_write_dqinfo(struct file *f, int type, struct if_dqinfo *info) return cfs_user_write(f, (char *)&dqinfo, sizeof(dqinfo), &offset); } +#ifdef HAVE_QUOTA64 +static int v3_write_dqheader(struct file *f, int type) +{ + static const __u32 quota_magics[] = V2_INITQMAGICS; + static const __u32 quota_versions[] = V2_INITQVERSIONS_R1; + struct v2_disk_dqheader dqhead; + loff_t offset = 0; + + CLASSERT(ARRAY_SIZE(quota_magics) == ARRAY_SIZE(quota_versions)); + LASSERT(0 <= type && type < ARRAY_SIZE(quota_magics)); + + dqhead.dqh_magic = cpu_to_le32(quota_magics[type]); + dqhead.dqh_version = cpu_to_le32(quota_versions[type]); + + return cfs_user_write(f, (char *)&dqhead, sizeof(dqhead), &offset); +} + +/* write dqinfo struct in a new quota file */ +static int v3_write_dqinfo(struct file *f, int type, struct if_dqinfo *info) +{ + return v2_write_dqinfo(f, type, info); +} +#endif + static int create_new_quota_files(struct qchk_ctxt *qctxt, struct obd_quotactl *oqc) { @@ -1836,34 +1901,50 @@ static int create_new_quota_files(struct qchk_ctxt *qctxt, struct if_dqinfo *info = qctxt->qckt_first_check[i]? NULL : &qctxt->qckt_dqinfo[i]; struct file *file; + const char *name[][MAXQUOTAS] = LUSTRE_OPQFILES_NAMES; + int (*write_dqheader)(struct file *, int); + int (*write_dqinfo)(struct file *, int, struct if_dqinfo *); if (!Q_TYPESET(oqc, i)) continue; - file = filp_open(op_quotafile[i], O_RDWR | O_CREAT | O_TRUNC, - 0644); + file = filp_open(name[oqc->qc_id][i], + O_RDWR | O_CREAT | O_TRUNC, 0644); if (IS_ERR(file)) { rc = PTR_ERR(file); CERROR("can't create %s file: rc = %d\n", - op_quotafile[i], rc); + name[oqc->qc_id][i], rc); GOTO(out, rc); } if (!S_ISREG(file->f_dentry->d_inode->i_mode)) { - CERROR("file %s is not regular", op_quotafile[i]); + CERROR("file %s is not regular", name[oqc->qc_id][i]); filp_close(file, 0); GOTO(out, rc = -EINVAL); } DQUOT_DROP(file->f_dentry->d_inode); - rc = v2_write_dqheader(file, i); + switch (oqc->qc_id) { + case LUSTRE_QUOTA_V1 : write_dqheader = v2_write_dqheader; + write_dqinfo = v2_write_dqinfo; + break; +#ifdef HAVE_QUOTA64 + case LUSTRE_QUOTA_V2 : write_dqheader = v3_write_dqheader; + write_dqinfo = v3_write_dqinfo; + break; +#endif + default : CERROR("unknown quota format!\n"); + LBUG(); + } + + rc = (*write_dqheader)(file, i); if (rc) { filp_close(file, 0); GOTO(out, rc); } - rc = v2_write_dqinfo(file, i, info); + rc = (*write_dqinfo)(file, i, info); filp_close(file, 0); if (rc) GOTO(out, rc); @@ -1959,12 +2040,12 @@ static int fsfilt_ext3_quotacheck(struct super_block *sb, if (!Q_TYPESET(oqc, i)) continue; - rc = quota_onoff(sb, Q_QUOTAON, i); + rc = quota_onoff(sb, Q_QUOTAON, i, oqc->qc_id); if (!rc || rc == -EBUSY) { rc = read_old_dqinfo(sb, i, qctxt->qckt_dqinfo); if (rc) GOTO(out, rc); - } else if (rc == -ENOENT) { + } else if (rc == -ENOENT || rc == -EINVAL || rc == -EEXIST) { qctxt->qckt_first_check[i] = 1; } else if (rc) { GOTO(out, rc); @@ -2032,14 +2113,14 @@ static int fsfilt_ext3_quotacheck(struct super_block *sb, } #endif /* turn off quota cause we are to dump chk_dqblk to files */ - quota_onoff(sb, Q_QUOTAOFF, oqc->qc_type); + quota_onoff(sb, Q_QUOTAOFF, oqc->qc_type, oqc->qc_id); rc = create_new_quota_files(qctxt, oqc); if (rc) GOTO(out, rc); /* we use vfs functions to set dqblk, so turn quota on */ - rc = quota_onoff(sb, Q_QUOTAON, oqc->qc_type); + rc = quota_onoff(sb, Q_QUOTAON, oqc->qc_type, oqc->qc_id); out: /* dump and free chk_dqblk */ rc = prune_chkquots(sb, qctxt, rc); @@ -2047,7 +2128,7 @@ out: /* turn off quota, `lfs quotacheck` will turn on when all * nodes quotacheck finish. */ - quota_onoff(sb, Q_QUOTAOFF, oqc->qc_type); + quota_onoff(sb, Q_QUOTAOFF, oqc->qc_type, oqc->qc_id); oqc->qc_stat = rc; if (rc) diff --git a/lustre/lvfs/lustre_quota_fmt.h b/lustre/lvfs/lustre_quota_fmt.h index b0638f5..2139ae0 100644 --- a/lustre/lvfs/lustre_quota_fmt.h +++ b/lustre/lvfs/lustre_quota_fmt.h @@ -183,7 +183,10 @@ int lustre_get_qids(struct file *fp, struct inode *inode, int type, struct list_head *list); -/* come from lustre_quota_fmt_conver.c */ +/* comes from lustre_quota_fmt_convert.c */ +int lustre_slave_quota_convert(lustre_quota_version_t qfmt, int type); int lustre_quota_convert(struct lustre_quota_info *lqi, int type); +#define LUSTRE_OPQFILES_NAMES { { "lquota.user", "lquota.group" }, \ + { "lquota_v2.user", "lquota_v2.group" } } #endif /* lustre_quota_fmt.h */ diff --git a/lustre/lvfs/lustre_quota_fmt_convert.c b/lustre/lvfs/lustre_quota_fmt_convert.c index 70350ed..baa37fb 100644 --- a/lustre/lvfs/lustre_quota_fmt_convert.c +++ b/lustre/lvfs/lustre_quota_fmt_convert.c @@ -51,7 +51,7 @@ static int admin_convert_dqinfo(struct file *fp_v1, struct file *fp_v2, return rc; } -static int admin_convert_v1_to_v2(struct file *fp_v1, struct file *fp_v2, +static int quota_convert_v1_to_v2(struct file *fp_v1, struct file *fp_v2, struct lustre_quota_info *lqi, int type) { struct list_head blk_list; @@ -158,7 +158,7 @@ int lustre_quota_convert(struct lustre_quota_info *lqi, int type) f_v1 = filp_open(name, O_RDONLY, 0); if (!IS_ERR(f_v1)) { if (!check_quota_file(f_v1, NULL, type, LUSTRE_QUOTA_V1)) { - rc = admin_convert_v1_to_v2(f_v1, f_v2, lqi, type); + rc = quota_convert_v1_to_v2(f_v1, f_v2, lqi, type); if (rc) CERROR("failed to convert v1 quota file" " to v2 quota file.\n"); @@ -181,5 +181,91 @@ int lustre_quota_convert(struct lustre_quota_info *lqi, int type) RETURN(rc); } - EXPORT_SYMBOL(lustre_quota_convert); + +#ifdef HAVE_QUOTA64 +/* + * convert operational quota files to the requested version + * returns: -ESTALE if upgrading to qfmt version is not supported + * -ENOMEM if memory was not allocated for conv. structures + * + * other error codes can be returned by VFS and have the + * appropriate meaning + */ +int lustre_slave_quota_convert(lustre_quota_version_t qfmt, int type) +{ + struct lustre_quota_info *lqi; + struct file *f_v1, *f_v2; + const char *name[][MAXQUOTAS] = LUSTRE_OPQFILES_NAMES; + int rc; + + ENTRY; + + /* we convert only to v2 version */ + if (qfmt != LUSTRE_QUOTA_V2) + GOTO(out, rc = -ESTALE); + + OBD_ALLOC_PTR(lqi); + if (lqi == NULL) + GOTO(out, rc = -ENOMEM); + + /* now that we support only v1 and v2 formats, + * only upgrade from v1 is possible, + * let's check if v1 file exists so that we convert it to v2 */ + f_v1 = filp_open(name[LUSTRE_QUOTA_V1][type], O_RDONLY, 0); + if (IS_ERR(f_v1)) + GOTO(out_free, rc = PTR_ERR(f_v1)); + + /* make sure it is really a v1 file */ + if (check_quota_file(f_v1, NULL, type, LUSTRE_QUOTA_V1)) + GOTO(out_f_v1, rc = -EINVAL); + + /* create new quota file for v2 version, follow the same rationale as + * mds_admin_quota_on: if the file already exists, then do not try to + * overwrite it, user has to fix the quotaon issue manually, + * e.g. through running quotacheck */ + f_v2 = filp_open(name[LUSTRE_QUOTA_V2][type], + O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0644); + if (IS_ERR(f_v2)) + GOTO(out_f_v1, rc = PTR_ERR(f_v2)); + + lqi->qi_version = LUSTRE_QUOTA_V2; + lqi->qi_files[type] = f_v2; + + /* initialize quota file with defaults, marking it invalid, + * this will help us not to get confused with partially converted + * operational quota files if we crash during conversion */ + rc = lustre_init_quota_info_generic(lqi, type, 1); + if (rc) + GOTO(out_f_v2, rc); + + rc = quota_convert_v1_to_v2(f_v1, f_v2, lqi, type); + if (!rc) { + /* we dont want good magic to store before the quota data, + * just to be safe if ldiskfs is running in writeback mode */ + LOCK_INODE_MUTEX(f_v2->f_dentry->d_inode); + rc = lustre_fsync(f_v2); + if (rc) + CERROR("error from fsync, rc=%d\n", rc); + UNLOCK_INODE_MUTEX(f_v2->f_dentry->d_inode); + + /* now that conversion successfully finished we mark + * this operational quota file with the correct magic, + * since this moment quotaon will treat it as a correct + * quota file */ + rc = lustre_init_quota_header(lqi, type, 0); + } + + EXIT; + +out_f_v2: + filp_close(f_v2, 0); +out_f_v1: + filp_close(f_v1, 0); +out_free: + OBD_FREE_PTR(lqi); +out: + return rc; +} +EXPORT_SYMBOL(lustre_slave_quota_convert); +#endif diff --git a/lustre/quota/quota_check.c b/lustre/quota/quota_check.c index bde6b6e..95bde12 100644 --- a/lustre/quota/quota_check.c +++ b/lustre/quota/quota_check.c @@ -118,6 +118,7 @@ int target_quota_check(struct obd_export *exp, struct obd_quotactl *oqctl) qta->qta_exp = exp; qta->qta_oqctl = *oqctl; + qta->qta_oqctl.qc_id = obt->obt_qfmt; /* override qfmt version */ qta->qta_sb = obt->obt_sb; qta->qta_sem = &obt->obt_quotachecking; diff --git a/lustre/quota/quota_context.c b/lustre/quota/quota_context.c index 7b7e23f..6f6efb8 100644 --- a/lustre/quota/quota_context.c +++ b/lustre/quota/quota_context.c @@ -951,8 +951,7 @@ qctxt_init(struct lustre_quota_ctxt *qctxt, struct super_block *sb, qctxt->lqc_cqs_least_bunit = PTLRPC_MAX_BRW_SIZE; qctxt->lqc_cqs_least_iunit = 2; qctxt->lqc_cqs_qs_factor = 2; - qctxt->lqc_atype = 0; - qctxt->lqc_status= 0; + qctxt->lqc_flags = 0; qctxt->lqc_bunit_sz = default_bunit_sz; qctxt->lqc_btune_sz = default_bunit_sz / 100 * default_btune_ratio; qctxt->lqc_iunit_sz = default_iunit_sz; diff --git a/lustre/quota/quota_ctl.c b/lustre/quota/quota_ctl.c index 8ab7c0e..e11473f 100644 --- a/lustre/quota/quota_ctl.c +++ b/lustre/quota/quota_ctl.c @@ -77,6 +77,9 @@ int mds_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl) case LUSTRE_Q_INVALIDATE: rc = mds_quota_invalidate(obd, oqctl); break; + case LUSTRE_Q_FINVALIDATE: + rc = mds_quota_finvalidate(obd, oqctl); + break; default: CERROR("%s: unsupported mds_quotactl command: %d\n", obd->obd_name, oqctl->qc_cmd); @@ -100,6 +103,7 @@ int filter_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl) ENTRY; switch (oqctl->qc_cmd) { + case Q_FINVALIDATE: case Q_QUOTAON: case Q_QUOTAOFF: if (!atomic_dec_and_test(&obt->obt_quotachecking)) { @@ -108,6 +112,12 @@ int filter_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl) rc = -EBUSY; break; } + if (oqctl->qc_cmd == Q_FINVALIDATE && + (obt->obt_qctxt.lqc_flags & UGQUOTA2LQC(oqctl->qc_type))) { + rc = -EBUSY; + break; + } + oqctl->qc_id = obt->obt_qfmt; /* override qfmt version */ case Q_GETOINFO: case Q_GETOQUOTA: case Q_GETQUOTA: @@ -121,13 +131,15 @@ int filter_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl) 1); push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); - rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl); + rc = fsfilt_quotactl(obd, obt->obt_sb, oqctl); pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); - if (oqctl->qc_cmd == Q_QUOTAON || oqctl->qc_cmd == Q_QUOTAOFF) { - if (!rc) - obt->obt_qctxt.lqc_status = - (oqctl->qc_cmd == Q_QUOTAON) ? 1 : 0; + if (oqctl->qc_cmd == Q_QUOTAON || oqctl->qc_cmd == Q_QUOTAOFF || + oqctl->qc_cmd == Q_FINVALIDATE) { + if (!rc && oqctl->qc_cmd == Q_QUOTAON) + obt->obt_qctxt.lqc_flags |= UGQUOTA2LQC(oqctl->qc_type); + if (!rc && oqctl->qc_cmd == Q_QUOTAOFF) + obt->obt_qctxt.lqc_flags &= ~UGQUOTA2LQC(oqctl->qc_type); atomic_inc(&obt->obt_quotachecking); } break; @@ -257,7 +269,7 @@ int lov_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl) if (oqctl->qc_cmd != Q_QUOTAON && oqctl->qc_cmd != Q_QUOTAOFF && oqctl->qc_cmd != Q_GETOQUOTA && oqctl->qc_cmd != Q_INITQUOTA && - oqctl->qc_cmd != Q_SETQUOTA) { + oqctl->qc_cmd != Q_SETQUOTA && oqctl->qc_cmd != Q_FINVALIDATE) { CERROR("bad quota opc %x for lov obd", oqctl->qc_cmd); RETURN(-EFAULT); } diff --git a/lustre/quota/quota_interface.c b/lustre/quota/quota_interface.c index 4680496..6f7e695 100644 --- a/lustre/quota/quota_interface.c +++ b/lustre/quota/quota_interface.c @@ -53,44 +53,64 @@ #define GROUP_QUOTA 2 #define MAX_STYPE_SIZE 5 + +/* The following information about CURRENT quotas is expected on the output: + * MDS: u for user quotas (administrative+operational) turned on, + * g for group quotas (administrative+operational) turned on, + * 1 for 32-bit operational quotas and 32-bit administrative quotas, + * 2 for 32-bit operational quotas and 64-bit administrative quotas, + * 3 for 64-bit operational quotas and 64-bit administrative quotas + * OST: u for user quotas (operational) turned on, + * g for group quotas (operational) turned on, + * 1 for 32-bit local operational quotas, + * 3 for 64-bit local operational quotas, + * Permanent parameters can be read with lctl (?) + */ int lprocfs_quota_rd_type(char *page, char **start, off_t off, int count, int *eof, void *data) { struct obd_device *obd = (struct obd_device *)data; char stype[MAX_STYPE_SIZE + 1] = ""; - int type = obd->u.obt.obt_qctxt.lqc_atype; - LASSERT(obd != NULL); + int oq_type, rc, is_mds; + lustre_quota_version_t aq_version, oq_version; + struct obd_device_target *obt; - if (type == 0) { - strcpy(stype, "off"); - } else { - if (type & USER_QUOTA) - strcat(stype, "u"); - if (type & GROUP_QUOTA) - strcat(stype, "g"); - } + LASSERT(obd != NULL); - /* append with quota version on MDS */ - if (!strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME)) { - int rc; - lustre_quota_version_t version; + obt = &obd->u.obt; + is_mds = !strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME); - rc = mds_quota_get_version(obd, &version); + /* Collect the needed information */ + oq_type = obd->u.obt.obt_qctxt.lqc_flags; + oq_version = obt->obt_qfmt; + if (is_mds) { + rc = mds_quota_get_version(obd, &aq_version); if (rc) - return rc; - - switch (version) { - case LUSTRE_QUOTA_V1: - strcat(stype, "1"); - break; - case LUSTRE_QUOTA_V2: - strcat(stype, "2"); - break; - default: - return -ENOSYS; - } + return -EPROTO; + /* Here we can also assert that aq_type == oq_type + * except for quota startup/shutdown states */ } + /* Transform the collected data into a user-readable string */ + if (oq_type & LQC_USRQUOTA_FLAG) + strcat(stype, "u"); + if (oq_type & LQC_GRPQUOTA_FLAG) + strcat(stype, "g"); + + if ((!is_mds || aq_version == LUSTRE_QUOTA_V1) && + oq_version == LUSTRE_QUOTA_V1) + strcat(stype, "1"); +#ifdef HAVE_QUOTA64 + else if ((!is_mds || aq_version == LUSTRE_QUOTA_V2) && + oq_version == LUSTRE_QUOTA_V2) + strcat(stype, "3"); +#endif + else if (is_mds && aq_version == LUSTRE_QUOTA_V2 && + oq_version == LUSTRE_QUOTA_V1) + strcat(stype, "2"); + else + return -EPROTO; + return snprintf(page, count, "%s\n", stype); } EXPORT_SYMBOL(lprocfs_quota_rd_type); @@ -100,63 +120,130 @@ static int auto_quota_on(struct obd_device *obd, int type, { struct obd_quotactl *oqctl; struct lvfs_run_ctxt saved; - int rc; + int rc = 0, id; + struct obd_device_target *obt; ENTRY; LASSERT(type == USRQUOTA || type == GRPQUOTA || type == UGQUOTA); - /* quota already turned on */ - if (obd->u.obt.obt_qctxt.lqc_status) - RETURN(0); + obt = &obd->u.obt; OBD_ALLOC_PTR(oqctl); if (!oqctl) RETURN(-ENOMEM); + if (!atomic_dec_and_test(&obt->obt_quotachecking)) { + CDEBUG(D_INFO, "other people are doing quotacheck\n"); + atomic_inc(&obt->obt_quotachecking); + RETURN(-EBUSY); + } + + id = UGQUOTA2LQC(type); + /* quota already turned on */ + if ((obt->obt_qctxt.lqc_flags & id) == id) { + rc = 0; + goto out; + } + oqctl->qc_type = type; oqctl->qc_cmd = Q_QUOTAON; - oqctl->qc_id = QFMT_LDISKFS; + oqctl->qc_id = obt->obt_qfmt; push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); + if (is_master) { + struct mds_obd *mds = &obd->u.mds; - if (!is_master) - goto local_quota; + down(&mds->mds_qonoff_sem); + /* turn on cluster wide quota */ + rc = mds_admin_quota_on(obd, oqctl); + if (rc) + CDEBUG(rc == -ENOENT ? D_QUOTA : D_ERROR, + "auto-enable admin quota failed. rc=%d\n", rc); + up(&mds->mds_qonoff_sem); - /* turn on cluster wide quota */ - rc = mds_admin_quota_on(obd, oqctl); - if (rc) { - CDEBUG(rc == -ENOENT ? D_QUOTA : D_ERROR, - "auto-enable admin quota failed. rc=%d\n", rc); - GOTO(out_pop, rc); } -local_quota: - /* turn on local quota */ - rc = fsfilt_quotactl(obd, sb, oqctl); - if (rc) { - CDEBUG(rc == -ENOENT ? D_QUOTA : D_ERROR, - "auto-enable local quota failed. rc=%d\n", rc); - if (is_master) - mds_quota_off(obd, oqctl); - } else { - obd->u.obt.obt_qctxt.lqc_status = 1; + if (!rc) { + /* turn on local quota */ + rc = fsfilt_quotactl(obd, sb, oqctl); + if (rc) + CDEBUG(rc == -ENOENT ? D_QUOTA : D_ERROR, + "auto-enable local quota failed. rc=%d\n", rc); + else + obt->obt_qctxt.lqc_flags |= UGQUOTA2LQC(type); } -out_pop: + pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); +out: + atomic_inc(&obt->obt_quotachecking); + OBD_FREE_PTR(oqctl); RETURN(rc); } +static int filter_quota_set_version(struct obd_device *obd, + lustre_quota_version_t version) +{ + struct obd_device_target *obt = &obd->u.obt; + + if (version != LUSTRE_QUOTA_V1) { +#ifdef HAVE_QUOTA64 + if (version != LUSTRE_QUOTA_V2) +#endif + return -EINVAL; + } + + if (!atomic_dec_and_test(&obt->obt_quotachecking)) { + CDEBUG(D_INFO, "other people are doing quotacheck\n"); + atomic_inc(&obt->obt_quotachecking); + return -EBUSY; + } + + if (obt->obt_qctxt.lqc_flags & (LQC_USRQUOTA_FLAG | LQC_GRPQUOTA_FLAG)) { + atomic_inc(&obt->obt_quotachecking); + return -EBUSY; + } + + obt->obt_qfmt = version; + + atomic_inc(&obt->obt_quotachecking); + + return 0; +} + +/* The following settings of CURRENT quotas is expected on the input: + * MDS: u for user quotas (administrative+operational) turned on, + * g for group quotas (administrative+operational) turned on, + * 1 for 32-bit operational quotas and 32-bit administrative quotas, + * 2 for 32-bit operational quotas and 64-bit administrative quotas, + * 3 for 64-bit operational quotas and 64-bit administrative quotas + * OST: u for user quotas (operational) turned on, + * g for group quotas (operational) turned on, + * 1 for 32-bit local operational quotas, + * 2 for 32-bit local operational quotas, + * 3 for 64-bit local operational quotas, + * Permanent parameters can be set with lctl/tunefs + */ int lprocfs_quota_wr_type(struct file *file, const char *buffer, unsigned long count, void *data) { struct obd_device *obd = (struct obd_device *)data; - struct obd_device_target *obt = &obd->u.obt; - int type = 0; + struct obd_device_target *obt; + int type = 0, is_mds, idx; unsigned long i; char stype[MAX_STYPE_SIZE + 1] = ""; + static const lustre_quota_version_t s2av[3] = {LUSTRE_QUOTA_V1, + LUSTRE_QUOTA_V2, + LUSTRE_QUOTA_V2}, + s2ov[3] = {LUSTRE_QUOTA_V1, + LUSTRE_QUOTA_V1, + LUSTRE_QUOTA_V2}; LASSERT(obd != NULL); + obt = &obd->u.obt; + + is_mds = !strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME); + if (count > MAX_STYPE_SIZE) return -EINVAL; @@ -175,22 +262,26 @@ int lprocfs_quota_wr_type(struct file *file, const char *buffer, break; /* quota version specifiers */ case '1' : - if (strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME)) - break; - - rc = mds_quota_set_version(obd, LUSTRE_QUOTA_V1); - if (rc) { - CDEBUG(D_QUOTA, "failed to set quota v1! %d\n", rc); - return rc; - } - break; case '2' : - if (strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME)) - break; - - rc = mds_quota_set_version(obd, LUSTRE_QUOTA_V2); + case '3' : + idx = stype[i] - '1'; +#ifndef HAVE_QUOTA64 + if (s2ov[idx] == LUSTRE_QUOTA_V2) + return -EINVAL; +#endif + if (is_mds) { + rc = mds_quota_set_version(obd, s2av[idx]); + if (rc) { + CDEBUG(D_QUOTA, "failed to set admin " + "quota to spec %c! %d\n", + stype[i], rc); + return rc; + } + } + rc = filter_quota_set_version(obd, s2ov[idx]); if (rc) { - CDEBUG(D_QUOTA, "could not set quota v2! %d\n", rc); + CDEBUG(D_QUOTA, "failed to set operational quota" + " to spec %c! %d\n", stype[i], rc); return rc; } break; @@ -199,17 +290,8 @@ int lprocfs_quota_wr_type(struct file *file, const char *buffer, } } - obt->obt_qctxt.lqc_atype = type; - - if (type == 0) - return count; - - if (!strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME)) - auto_quota_on(obd, type - 1, obt->obt_sb, 1); - else if (!strcmp(obd->obd_type->typ_name, LUSTRE_OST_NAME)) - auto_quota_on(obd, type - 1, obt->obt_sb, 0); - else - return -EFAULT; + if (type != 0) + auto_quota_on(obd, type - 1, obt->obt_sb, is_mds); return count; } @@ -223,12 +305,16 @@ static int filter_quota_setup(struct obd_device *obd) struct obd_device_target *obt = &obd->u.obt; ENTRY; +#ifdef HAVE_QUOTA64 + obt->obt_qfmt = LUSTRE_QUOTA_V2; +#else + obt->obt_qfmt = LUSTRE_QUOTA_V1; +#endif atomic_set(&obt->obt_quotachecking, 1); rc = qctxt_init(&obt->obt_qctxt, obt->obt_sb, NULL); - if (rc) { + if (rc) CERROR("initialize quota context failed! (rc:%d)\n", rc); - RETURN(rc); - } + RETURN(rc); } @@ -582,6 +668,11 @@ static int mds_quota_setup(struct obd_device *obd) int rc; ENTRY; +#ifdef HAVE_QUOTA64 + obt->obt_qfmt = LUSTRE_QUOTA_V2; +#else + obt->obt_qfmt = LUSTRE_QUOTA_V1; +#endif mds->mds_quota_info.qi_version = LUSTRE_QUOTA_V2; atomic_set(&obt->obt_quotachecking, 1); /* initialize quota master and quota context */ diff --git a/lustre/quota/quota_internal.h b/lustre/quota/quota_internal.h index 3b32102..fb5fd93 100644 --- a/lustre/quota/quota_internal.h +++ b/lustre/quota/quota_internal.h @@ -98,6 +98,7 @@ int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl); int mds_quota_get_version(struct obd_device *obd, lustre_quota_version_t *ver); int mds_quota_set_version(struct obd_device *obd, lustre_quota_version_t ver); int mds_quota_invalidate(struct obd_device *obd, struct obd_quotactl *oqctl); +int mds_quota_finvalidate(struct obd_device *obd, struct obd_quotactl *oqctl); int mds_admin_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl); int mds_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl); diff --git a/lustre/quota/quota_master.c b/lustre/quota/quota_master.c index 4d67195..5187733 100644 --- a/lustre/quota/quota_master.c +++ b/lustre/quota/quota_master.c @@ -537,8 +537,7 @@ int mds_quota_set_version(struct obd_device *obd, lustre_quota_version_t version struct lustre_quota_info *qinfo = &mds->mds_quota_info; int rc = 0, i; - if (version != LUSTRE_QUOTA_V1 && - version != LUSTRE_QUOTA_V2) + if (version != LUSTRE_QUOTA_V1 && version != LUSTRE_QUOTA_V2) return -EINVAL; down(&mds->mds_qonoff_sem); @@ -597,7 +596,7 @@ int mds_quota_invalidate(struct obd_device *obd, struct obd_quotactl *oqctl) LASSERT(strlen(quotafile) + sizeof(prefix) <= sizeof(name)); sprintf(name, "%s%s", prefix, quotafile); - fp = filp_open(name, O_CREAT | O_TRUNC, 0644); + fp = filp_open(name, O_CREAT | O_TRUNC | O_RDWR, 0644); if (IS_ERR(fp)) { rc = PTR_ERR(fp); CERROR("error invalidating admin quotafile %s (rc:%d)\n", @@ -615,6 +614,27 @@ out: return rc; } +int mds_quota_finvalidate(struct obd_device *obd, struct obd_quotactl *oqctl) +{ + struct mds_obd *mds = &obd->u.mds; + int rc; + struct lvfs_run_ctxt saved; + + push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); + down(&mds->mds_qonoff_sem); + + oqctl->qc_cmd = Q_FINVALIDATE; + oqctl->qc_id = obd->u.obt.obt_qfmt; + rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl); + if (!rc) + rc = obd_quotactl(mds->mds_osc_exp, oqctl); + + up(&mds->mds_qonoff_sem); + pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); + + return rc; +} + int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl) { struct mds_obd *mds = &obd->u.mds; @@ -681,7 +701,7 @@ int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl) rc == -ENOENT ? "creating" : "overwriting"); /* create quota file overwriting old if needed */ - fp = filp_open(name, O_CREAT | O_TRUNC, 0644); + fp = filp_open(name, O_CREAT | O_TRUNC | O_RDWR, 0644); if (IS_ERR(fp)) { rc = PTR_ERR(fp); CERROR("error creating admin quotafile %s (rc:%d)\n", @@ -770,7 +790,7 @@ int mds_admin_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl) qinfo->qi_version == LUSTRE_QUOTA_V2) { CDEBUG(D_INFO, "attempting to convert V1 quota file to" " V2 format\n"); - fp = filp_open(name, O_CREAT | O_TRUNC, 0644); + fp = filp_open(name, O_CREAT | O_TRUNC | O_RDWR, 0644); if (!IS_ERR(fp)) { qinfo->qi_files[i] = fp; rc = fsfilt_quotainfo(obd, qinfo, i, QFILE_CONVERT); @@ -850,7 +870,7 @@ int mds_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl) rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl); if (!rc) - obt->obt_qctxt.lqc_status = 1; + obt->obt_qctxt.lqc_flags |= UGQUOTA2LQC(oqctl->qc_type); out: pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); up(&mds->mds_qonoff_sem); @@ -880,7 +900,7 @@ int mds_quota_off(struct obd_device *obd, struct obd_quotactl *oqctl) rc = obd_quotactl(mds->mds_osc_exp, oqctl); rc2 = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl); if (!rc2) - obt->obt_qctxt.lqc_status = 0; + obt->obt_qctxt.lqc_flags &= ~UGQUOTA2LQC(oqctl->qc_type); pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); up(&mds->mds_qonoff_sem); diff --git a/lustre/quota/quotactl_test.c b/lustre/quota/quotactl_test.c index 90cb5b9..bf5b145 100644 --- a/lustre/quota/quotactl_test.c +++ b/lustre/quota/quotactl_test.c @@ -33,7 +33,7 @@ static int quotactl_test_1(struct obd_device *obd, struct super_block *sb) ENTRY; oqctl.qc_cmd = Q_QUOTAON; - oqctl.qc_id = QFMT_LDISKFS; + oqctl.qc_id = obd->u.obt.obt_qfmt; oqctl.qc_type = UGQUOTA; rc = fsfilt_quotactl(obd, sb, &oqctl); if (rc) diff --git a/lustre/tests/sanity-quota.sh b/lustre/tests/sanity-quota.sh index bd5c12b..b8164a5 100644 --- a/lustre/tests/sanity-quota.sh +++ b/lustre/tests/sanity-quota.sh @@ -1131,12 +1131,24 @@ test_14a() { # was test_14 b=12223 -- setting quota on root } run_test 14a "test setting quota on root ===" +# set quota version (both administrative and operational quotas) quota_set_version() { - local qver=$1 - do_facet mds "lctl set_param mds.${FSNAME}-MDT*.quota_type=$qver" + do_facet mds "lctl set_param mds.${FSNAME}-MDT*.quota_type=$1" + for j in `seq $OSTCOUNT`; do + do_facet ost$j "lctl set_param obdfilter.*.quota_type=$1" + done +} + +# save quota version (both administrative and operational quotas) +quota_save_version() { + do_facet mgs "lctl conf_param ${FSNAME}-MDT*.mdt.quota_type=$1" + do_facet mgs "lctl conf_param ${FSNAME}-OST*.ost.quota_type=$1" } -test_14b() { # was test_14a +test_14b(){ + local l + local CURSPACE + # 1. check that required users exist # 2. ensure that switch to new mode will start conversion # 3. start quota in old mode and put some entries @@ -1146,7 +1158,7 @@ test_14b() { # was test_14a MISSING_USERS="" for i in `seq 1 30`; do - check_runas_id_ret quota15_$i "runas -u quota15_$i" + check_runas_id_ret quota15_$i "runas -u quota15_$i" >/dev/null 2>/dev/null if [ "$?" != "0" ]; then MISSING_USERS="$MISSING_USERS quota15_$i" fi @@ -1158,23 +1170,48 @@ test_14b() { # was test_14a fi $LFS quotaoff -ug $DIR + echo "setting quota version 1" quota_set_version 1 + echo "running quotacheck" $LFS quotacheck -ug $DIR + chmod 0777 $DIR/$tdir + for i in `seq 1 30`; do + l=$[$i*1024*128] # set limits in 128 Mb units + $LFS setquota -u quota15_$i $l $l $l $l $DIR || error "lfs setquota failed" + runas -u quota15_$i dd if=/dev/zero of="$DIR/$tdir/quota15_$i" \ + bs=1048576 count=$[($i+1)/2] || error "dd failed" + done + cancel_lru_locks osc + + echo "saving quota data" for i in `seq 1 30`; do - $LFS setquota -u quota15_$i -b $i -B $i -i $i -I $i $DIR + CURSPACE[$i]=`$LFS quota -u quota15_$i $MOUNT | awk '{if(start) {start=0; sum += $1} if(($1 ~ /OST/) && (NF==1)) {start=1;} + if(($1 ~ /OST/) && (NF != 1)) {sum += $2}; } END { print sum }'` done $LFS quotaoff -ug $DIR - quota_set_version 2 + echo "setting version 3 or 2 (dependent on the kernel support)" + quota_set_version 3 2>&1 | grep "Invalid argument" && quota_set_version 2 + + echo "invalidating quota files" $LFS quotainv -ug $DIR + $LFS quotainv -ugf $DIR $LFS quotacheck -ug $DIR for i in `seq 1 30`; do + l=$[$i*1024*128] # the format is "mntpnt curspace[*] bsoftlimit bhardlimit [time] curinodes[*] isoftlimit ihardlimit" - ($LFS quota -u quota15_$i $DIR | grep -E '^ *'$DIR' *[0-9]+\** *'$i' *'$i' *[0-9]+\** *'$i' *'$i) \ - || error "lfs quota output is unexpected" - $LFS setquota -u quota15_$i -b 0 -B 0 -i 0 -I 0 $DIR + echo "checking administrative quota migration results for user quota15_$i" + $LFS quota -u quota15_$i $DIR | grep -E '^ *'$MOUNT' *[0-9]+\** *'$l' *'$l' *[0-9]+\** *'$l' *'$l \ + || error "lfs quota output is unexpected" + echo "checking operational quota migration results for user quota15_$i, curspace should be ${CURSPACE[$i]}" + l=`$LFS quota -u quota15_$i $MOUNT | awk '{if(start) {start=0; sum += $1} if(($1 ~ /OST/) && (NF==1)) {start=1;} + if(($1 ~ /OST/) && (NF != 1)) {sum += $2}; } END { print sum }'` + echo "...real is $l" + [ "$l" -eq "${CURSPACE[$i]}" ] || error "curspace mismatch" + rm $DIR/$tdir/quota15_$i || error "could not remove quota15_$i" + $LFS setquota -u quota15_$i 0 0 0 0 $DIR || error "ifs setquota clear failed" done } run_test 14b "setting 30 quota entries in quota v1 file before conversion ===" @@ -1582,6 +1619,31 @@ test_21() { } run_test 21 "run for fixing bug16053 ===========" +test_22() { + local SAVEREFORMAT + + SAVEREFORMAT=$REFORMAT + $LFS quotaoff -ug $DIR || error "could not turn quotas off" + quota_set_version "1" + $LFS quotacheck -ug $DIR || error "quotacheck failed" + + quota_save_version "ug1" + + REFORMAT="reformat" + stopall + mount + setupall + REFORMAT=$SAVEREFORMAT + + echo "checking parameters" + + do_facet mds "lctl get_param mds.${FSNAME}-MDT*.quota_type" | grep "ug1" || error "admin failure" + do_facet ost1 "lctl get_param obdfilter.*.quota_type" | grep "ug1" || error "op failure" + + run_test 0 "reboot lustre" +} +run_test 22 "test if quota_type saved as permanent parameter ====" + # turn off quota test_99() { diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index 216bd08..45d5f80 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -1251,7 +1251,6 @@ static int lfs_quotacheck(int argc, char **argv) memset(&qctl, 0, sizeof(qctl)); qctl.qc_cmd = LUSTRE_Q_QUOTAOFF; - qctl.qc_id = QFMT_LDISKFS; qctl.qc_type = check_type; rc = llapi_quotactl(mnt, &qctl); if (rc) { @@ -1276,7 +1275,6 @@ static int lfs_quotacheck(int argc, char **argv) memset(&qctl, 0, sizeof(qctl)); qctl.qc_cmd = LUSTRE_Q_QUOTAON; - qctl.qc_id = QFMT_LDISKFS; qctl.qc_type = check_type; rc = llapi_quotactl(mnt, &qctl); if (rc) { @@ -1301,7 +1299,6 @@ static int lfs_quotaon(int argc, char **argv) memset(&qctl, 0, sizeof(qctl)); qctl.qc_cmd = LUSTRE_Q_QUOTAON; - qctl.qc_id = QFMT_LDISKFS; optind = 0; while ((c = getopt(argc, argv, "ugf")) != -1) { @@ -1409,7 +1406,7 @@ static int lfs_quotainv(int argc, char **argv) qctl.qc_cmd = LUSTRE_Q_INVALIDATE; optind = 0; - while ((c = getopt(argc, argv, "ug")) != -1) { + while ((c = getopt(argc, argv, "ugf")) != -1) { switch (c) { case 'u': qctl.qc_type |= 0x01; @@ -1417,6 +1414,9 @@ static int lfs_quotainv(int argc, char **argv) case 'g': qctl.qc_type |= 0x02; break; + case 'f': + qctl.qc_cmd = LUSTRE_Q_FINVALIDATE; + break; default: fprintf(stderr, "error: %s: option '-%c' " "unrecognized\n", argv[0], c); diff --git a/lustre/utils/lustre_cfg.c b/lustre/utils/lustre_cfg.c index c9337bf..9d382a3 100644 --- a/lustre/utils/lustre_cfg.c +++ b/lustre/utils/lustre_cfg.c @@ -732,8 +732,8 @@ int jt_lcfg_setparam(int argc, char **argv) rc = write(fp, value, strlen(value)); if (rc < 0) fprintf(stderr, - "error writing to file %s\n", - glob_info.gl_pathv[i]); + "error writing to file %s (%s)\n", + glob_info.gl_pathv[i], strerror(errno)); else rc = 0; close(fp); -- 1.8.3.1