Whamcloud - gitweb
Branch b1_8
authoranserper <anserper>
Sun, 6 Jul 2008 17:37:12 +0000 (17:37 +0000)
committeranserper <anserper>
Sun, 6 Jul 2008 17:37:12 +0000 (17:37 +0000)
b=13904
i=Johann Lombardi(johann)
i=ZhiYong Tian(tianzy)

Adding 64-bit quota file support

20 files changed:
lustre/autoconf/lustre-core.m4
lustre/doc/lfs.1
lustre/include/lustre/lustre_idl.h
lustre/include/lustre/lustre_user.h
lustre/include/lustre_quota.h
lustre/include/obd.h
lustre/llite/dir.c
lustre/lvfs/fsfilt_ext3.c
lustre/lvfs/lustre_quota_fmt.h
lustre/lvfs/lustre_quota_fmt_convert.c
lustre/quota/quota_check.c
lustre/quota/quota_context.c
lustre/quota/quota_ctl.c
lustre/quota/quota_interface.c
lustre/quota/quota_internal.h
lustre/quota/quota_master.c
lustre/quota/quotactl_test.c
lustre/tests/sanity-quota.sh
lustre/utils/lfs.c
lustre/utils/lustre_cfg.c

index 97edc50..2792f61 100644 (file)
@@ -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 <linux/kernel.h>
+        #include <linux/fs.h>
+        #include <linux/quotaio_v2.h>
+        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
index 3bc9186..d00fcac 100644 (file)
@@ -33,7 +33,7 @@ lfs \- Lustre utility to create a file with specific striping pattern, find the
 .br
 .B lfs quotaoff [-ug] <filesystem>
 .br
-.B lfs quotainv [-ug] <filesystem>
+.B lfs quotainv [-ug] [-f] <filesystem>
 .br
 .B lfs setquota [-u|--user|-g|--group] <username|groupname>
              \fB[--block-softlimit <block-softlimit>]
@@ -117,8 +117,8 @@ To turn filesystem quotas on. Options specify quota for users (-u) groups (-g) a
 .B quotaoff [-ugf] <filesystem>
 To turn filesystem quotas off.  Options specify quota for users (-u) groups (-g) and force (-f)
 .TP
-.B quotainv [-ug] <filesystem>
-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] <filesystem>
+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] <name> [--block-softlimit <block-softlimit>] [--block-hardlimit <block-hardlimit>] [--inode-softlimit <inode-softlimit>] [--inode-hardlimit <inode-hardlimit>] <filesystem>
 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
index 84fe7d7..dace6cc 100644 (file)
@@ -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)
index 8a883e8..a87cf82 100644 (file)
@@ -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;
index eb8b227..a2d3635 100644 (file)
@@ -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
index 7267fba..88a81a3 100644 (file)
@@ -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);
index 323bebd..ee9b255 100644 (file)
@@ -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:
index d0e1f88..88bf8dd 100644 (file)
@@ -60,6 +60,8 @@
 #include <linux/ext3_extents.h>
 #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)
index b0638f5..2139ae0 100644 (file)
@@ -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 */
index 70350ed..baa37fb 100644 (file)
@@ -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
index bde6b6e..95bde12 100644 (file)
@@ -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;
 
index 7b7e23f..6f6efb8 100644 (file)
@@ -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;
index 8ab7c0e..e11473f 100644 (file)
@@ -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);
         }
index 4680496..6f7e695 100644 (file)
 #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 */
index 3b32102..fb5fd93 100644 (file)
@@ -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);
index 4d67195..5187733 100644 (file)
@@ -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);
index 90cb5b9..bf5b145 100644 (file)
@@ -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)
index bd5c12b..b8164a5 100644 (file)
@@ -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()
 {
index 216bd08..45d5f80 100644 (file)
@@ -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);
index c9337bf..9d382a3 100644 (file)
@@ -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);