Whamcloud - gitweb
Land b_head_quota onto HEAD (20081116_0105)
authorfanyong <fanyong>
Sat, 15 Nov 2008 18:39:35 +0000 (18:39 +0000)
committerfanyong <fanyong>
Sat, 15 Nov 2008 18:39:35 +0000 (18:39 +0000)
b=13058
i=johann
i=yury.umanets

143 files changed:
lustre/ChangeLog
lustre/Makefile.in
lustre/autoMakefile.am
lustre/autoconf/lustre-core.m4
lustre/cmm/cmm_device.c
lustre/cmm/cmm_object.c
lustre/cmm/mdc_device.c
lustre/doc/lfs.1
lustre/fid/fid_store.c
lustre/fld/fld_index.c
lustre/include/class_hash.h
lustre/include/dt_object.h
lustre/include/linux/lustre_acl.h
lustre/include/linux/lustre_compat25.h
lustre/include/linux/lustre_fsfilt.h
lustre/include/linux/lustre_user.h
lustre/include/lprocfs_status.h
lustre/include/lustre/liblustreapi.h
lustre/include/lustre/lustre_idl.h
lustre/include/lustre/lustre_user.h
lustre/include/lustre_capa.h
lustre/include/lustre_export.h
lustre/include/lustre_lib.h
lustre/include/lustre_net.h
lustre/include/lustre_quota.h
lustre/include/lustre_req_layout.h
lustre/include/lustre_sec.h
lustre/include/md_object.h
lustre/include/obd.h
lustre/include/obd_class.h
lustre/include/obd_ost.h
lustre/include/obd_support.h
lustre/kernel_patches/patches/quota-fix-oops-in-invalidate_dquots.patch [new file with mode: 0644]
lustre/kernel_patches/patches/quota-large-limits-rhel5.patch [new file with mode: 0644]
lustre/kernel_patches/patches/quota-large-limits-sles10.patch [new file with mode: 0644]
lustre/kernel_patches/series/2.6-rhel5.series
lustre/kernel_patches/series/2.6-sles10.series
lustre/kernel_patches/series/2.6.22-vanilla.series
lustre/ldlm/ldlm_lib.c
lustre/ldlm/ldlm_lock.c
lustre/ldlm/ldlm_lockd.c
lustre/liblustre/Makefile.am
lustre/liblustre/file.c
lustre/liblustre/lutil.c
lustre/llite/dir.c
lustre/llite/llite_capa.c
lustre/llite/llite_lib.c
lustre/llite/namei.c
lustre/lmv/lmv_obd.c
lustre/lov/lov_obd.c
lustre/lov/lov_request.c
lustre/lvfs/autoMakefile.am
lustre/lvfs/fsfilt_ext3.c
lustre/lvfs/fsfilt_reiserfs.c
lustre/lvfs/lustre_quota_fmt.c
lustre/lvfs/lustre_quota_fmt.h
lustre/lvfs/quotafmt_test.c
lustre/mdc/mdc_internal.h
lustre/mdc/mdc_request.c
lustre/mdd/Makefile.in
lustre/mdd/mdd_device.c
lustre/mdd/mdd_dir.c
lustre/mdd/mdd_internal.h
lustre/mdd/mdd_lov.c
lustre/mdd/mdd_lproc.c
lustre/mdd/mdd_object.c
lustre/mdd/mdd_orphans.c
lustre/mdd/mdd_permission.c
lustre/mdd/mdd_quota.c [new file with mode: 0644]
lustre/mdd/mdd_trans.c
lustre/mds/handler.c
lustre/mds/lproc_mds.c
lustre/mds/mds_fs.c
lustre/mds/mds_internal.h
lustre/mds/mds_lov.c
lustre/mdt/mdt_handler.c
lustre/mdt/mdt_identity.c
lustre/mdt/mdt_idmap.c
lustre/mdt/mdt_internal.h
lustre/mdt/mdt_lib.c
lustre/mdt/mdt_lproc.c
lustre/mdt/mdt_open.c
lustre/mdt/mdt_recovery.c
lustre/mdt/mdt_reint.c
lustre/mdt/mdt_xattr.c
lustre/obdclass/capa.c
lustre/obdclass/class_obd.c
lustre/obdclass/genops.c
lustre/obdclass/llog_lvfs.c
lustre/obdclass/lprocfs_status.c
lustre/obdclass/lu_object.c
lustre/obdclass/obd_config.c
lustre/obdecho/echo.c
lustre/obdecho/echo_client.c
lustre/obdfilter/filter.c
lustre/obdfilter/filter_capa.c
lustre/obdfilter/filter_internal.h
lustre/obdfilter/filter_io.c
lustre/obdfilter/filter_io_26.c
lustre/obdfilter/filter_log.c
lustre/obdfilter/lproc_obdfilter.c
lustre/osc/osc_cl_internal.h
lustre/osc/osc_io.c
lustre/osc/osc_page.c
lustre/osc/osc_request.c
lustre/osd/osd_handler.c
lustre/osd/osd_internal.h
lustre/osd/osd_oi.c
lustre/osd/osd_oi.h
lustre/ost/ost_handler.c
lustre/ptlrpc/layout.c
lustre/ptlrpc/lproc_ptlrpc.c
lustre/ptlrpc/pack_generic.c
lustre/ptlrpc/ptlrpc_module.c
lustre/ptlrpc/recover.c
lustre/ptlrpc/sec.c
lustre/ptlrpc/service.c
lustre/ptlrpc/wiretest.c
lustre/quota/Makefile.in
lustre/quota/autoMakefile.am
lustre/quota/lproc_quota.c [new file with mode: 0644]
lustre/quota/quota_adjust_qunit.c [new file with mode: 0644]
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/tests/acceptance-small.sh
lustre/tests/cfg/insanity-lmv.sh
lustre/tests/cfg/lmv.sh
lustre/tests/cfg/local.sh
lustre/tests/sanity-quota.sh
lustre/tests/sanity-sec.sh
lustre/tests/sanity.sh
lustre/tests/test-framework.sh
lustre/utils/l_getidentity.c
lustre/utils/lfs.c
lustre/utils/liblustreapi.c
lustre/utils/lmc
lustre/utils/req-layout.c
lustre/utils/wirecheck.c
lustre/utils/wiretest.c

index 6a4513f..0026ea9 100644 (file)
@@ -66,6 +66,15 @@ Description: Hitting mdc_commit_close() ASSERTION
 Details    : Properly handle request reference release in
             ll_release_openhandle().
 
+Severity   : major
+Bugzilla   : 14840
+Description: quota recovery deadlock during mds failover
+Details    : This patch includes att18982, att18236, att18237 in bz14840.
+             Slove the problems:
+             1. fix osts hang when mds does failover with quotaon
+             2. prevent watchdog storm when osts threads wait for the
+               recovery of mds
+
 Severity   : normal
 Bugzilla   : 15975
 Frequency  : only patchless client
@@ -150,6 +159,23 @@ Details    : Apply the MGS_CONNECT_SUPPORTED mask at reconnect time so
             the connect flags are properly negotiated.
 
 Severity   : normal
+Frequency  : often
+Bugzilla   : 16125
+Description: quotas are not honored with O_DIRECT
+Details    : all writes with the flag O_DIRECT will use grants which leads to
+            this problem. Now using OBD_BRW_SYNC to guard this.
+
+Severity   : normal
+Bugzilla   : 15058
+Description: add quota statistics
+Details    : 1. sort out quota proc entries and proc code.
+            2. add quota statistics
+
+Severity   : enhancement
+Bugzilla   : 13058
+Description: enable quota support for HEAD.
+
+Severity   : normal
 Bugzilla   : 16006
 Description: Properly propagate oinfo flags from lov to osc for statfs
 Details    : restore missing copy oi_flags to lov requests.
index 82c5433..f1c44fa 100644 (file)
@@ -6,9 +6,9 @@ subdir-m += ptlrpc
 subdir-m += osc
 subdir-m += obdecho
 subdir-m += mgc
+subdir-m += quota
 
 @SERVER_TRUE@subdir-m += mds obdfilter ost mgs mdt cmm mdd osd
 @CLIENT_TRUE@subdir-m += mdc lmv llite fld
-@QUOTA_TRUE@subdir-m += quota
 
 @INCLUDE_RULES@
index 3ad4024..51658ae 100644 (file)
@@ -58,9 +58,7 @@ if CLIENT
 SUBDIRS += $(CLIENT_SUBDIRS)
 endif
 
-if QUOTA
 SUBDIRS += $(QUOTA_SUBDIRS)
-endif
 
 # this needs to be after the client subdirs
 if LIBLUSTRE
index 2a87e8f..317d3c2 100644 (file)
@@ -703,6 +703,18 @@ LB_LINUX_CONFIG_IM([CRYPTO_SHA1],[],[
 ])
 ])
 
+#
+# LC_CONFIG_RMTCLIENT
+#
+dnl FIXME
+dnl the AES symbol usually tied with arch, e.g. CRYPTO_AES_586
+dnl FIXME
+AC_DEFUN([LC_CONFIG_RMTCLIENT],
+[LB_LINUX_CONFIG_IM([CRYPTO_AES],[],[
+       AC_MSG_ERROR([Lustre remote client require that CONFIG_CRYPTO_AES is enabled in your kernel.])
+])
+])
+
 AC_DEFUN([LC_SUNRPC_CACHE],
 [AC_MSG_CHECKING([if sunrpc struct cache_head uses kref])
 LB_LINUX_TRY_COMPILE([
@@ -784,11 +796,6 @@ AC_DEFUN([LC_CONFIG_GSS],
                            [AC_MSG_WARN([kernel TWOFISH support is recommended by using GSS.])])
         LB_LINUX_CONFIG_IM([CRYPTO_CAST6],[],
                            [AC_MSG_WARN([kernel CAST6 support is recommended by using GSS.])])
-       dnl FIXME
-       dnl the AES symbol usually tied with arch, e.g. CRYPTO_AES_586
-       dnl FIXME
-       LB_LINUX_CONFIG_IM([CRYPTO_AES],[],
-                           [AC_MSG_WARN([kernel AES support is recommended by using GSS.])])
 
        AC_CHECK_LIB([gssapi], [gss_init_sec_context],
                      [GSSAPI_LIBS="$GSSAPI_LDFLAGS -lgssapi"],
@@ -1551,9 +1558,9 @@ AC_DEFUN([LC_PROG_LINUX],
          LC_CONFIG_PINGER
          LC_CONFIG_CHECKSUM
          LC_CONFIG_LIBLUSTRE_RECOVERY
-         LC_CONFIG_QUOTA
          LC_CONFIG_HEALTH_CHECK_WRITE
          LC_CONFIG_LRU_RESIZE
+         LC_QUOTA_MODULE
 
          LC_TASK_PPTR
          # RHEL4 patches
@@ -1591,6 +1598,7 @@ AC_DEFUN([LC_PROG_LINUX],
 
          LC_FUNC_SET_FS_PWD
          LC_CAPA_CRYPTO
+         LC_CONFIG_RMTCLIENT
          LC_CONFIG_GSS
          LC_FUNC_MS_FLOCK_LOCK
          LC_FUNC_HAVE_CAN_SLEEP_ARG
@@ -1599,6 +1607,7 @@ AC_DEFUN([LC_PROG_LINUX],
          LC_COOKIE_FOLLOW_LINK
          LC_FUNC_RCU
          LC_PERCPU_COUNTER
+         LC_QUOTA64
 
          # does the kernel have VFS intent patches?
          LC_VFS_INTENT_PATCHES
@@ -1645,7 +1654,7 @@ AC_DEFUN([LC_PROG_LINUX],
 
          # raid5-zerocopy patch
          LC_PAGE_CONSTANT
-               
+
         # 2.6.22
          LC_INVALIDATE_BDEV_2ARG
          LC_ASYNC_BLOCK_CIPHER
@@ -1778,50 +1787,35 @@ fi
 #
 # LC_CONFIG_QUOTA
 #
-# whether to enable quota support
+# whether to enable quota support global control
 #
 AC_DEFUN([LC_CONFIG_QUOTA],
 [AC_ARG_ENABLE([quota],
        AC_HELP_STRING([--enable-quota],
                        [enable quota support]),
-       [],[enable_quota='default'])
-if test x$linux25 != xyes; then
-       enable_quota='no'
-fi
-LB_LINUX_CONFIG([QUOTA],[
-       if test x$enable_quota = xdefault; then
-               enable_quota='yes'
-       fi
-],[
-       if test x$enable_quota = xdefault; then
-               enable_quota='no'
-               AC_MSG_WARN([quota is not enabled because the kernel lacks quota support])
-       else
-               if test x$enable_quota = xyes; then
-                       AC_MSG_ERROR([cannot enable quota because the kernel lacks quota support])
-               fi
-       fi
+       [],[enable_quota='yes'])
 ])
-if test x$enable_quota != xno; then
+
+# whether to enable quota support(kernel modules)
+AC_DEFUN([LC_QUOTA_MODULE],
+[if test x$enable_quota != xno; then
+    LB_LINUX_CONFIG([QUOTA],[
+       enable_quota_module='yes'
        AC_DEFINE(HAVE_QUOTA_SUPPORT, 1, [Enable quota support])
+    ],[
+       enable_quota_module='no'
+       AC_MSG_WARN([quota is not enabled because the kernel - lacks quota support])
+    ])
 fi
 ])
 
-#
-# LC_CONFIG_SPLIT
-#
-# whether to enable split support
-#
-AC_DEFUN([LC_CONFIG_SPLIT],
-[AC_MSG_CHECKING([whether to enable split support])
-AC_ARG_ENABLE([split],
-       AC_HELP_STRING([--enable-split],
-                       [enable split support]),
-       [],[enable_split='no'])
-AC_MSG_RESULT([$enable_split])
-if test x$enable_split != xno; then
-   AC_DEFINE(HAVE_SPLIT_SUPPORT, 1, [enable split support])
-fi
+AC_DEFUN([LC_QUOTA],
+[#check global
+LC_CONFIG_QUOTA
+#check for utils
+AC_CHECK_HEADER(sys/quota.h,
+                [AC_DEFINE(HAVE_SYS_QUOTA_H, 1, [Define to 1 if you have <sys/quota.h>.])],
+                [AC_MSG_ERROR([don't find <sys/quota.h> in your system])])
 ])
 
 AC_DEFUN([LC_QUOTA_READ],
@@ -1840,6 +1834,23 @@ LB_LINUX_TRY_COMPILE([
 ])
 
 #
+# LC_CONFIG_SPLIT
+#
+# whether to enable split support
+#
+AC_DEFUN([LC_CONFIG_SPLIT],
+[AC_MSG_CHECKING([whether to enable split support])
+AC_ARG_ENABLE([split],
+       AC_HELP_STRING([--enable-split],
+                       [enable split support]),
+       [],[enable_split='no'])
+AC_MSG_RESULT([$enable_split])
+if test x$enable_split != xno; then
+   AC_DEFINE(HAVE_SPLIT_SUPPORT, 1, [enable split support])
+fi
+])
+
+#
 # LC_COOKIE_FOLLOW_LINK
 #
 # kernel 2.6.13+ ->follow_link returns a cookie
@@ -1942,6 +1953,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
@@ -2046,7 +2081,7 @@ AM_CONDITIONAL(LIBLUSTRE_TESTS, test x$enable_liblustre_tests = xyes)
 AM_CONDITIONAL(MPITESTS, test x$enable_mpitests = xyes, Build MPI Tests)
 AM_CONDITIONAL(CLIENT, test x$enable_client = xyes)
 AM_CONDITIONAL(SERVER, test x$enable_server = xyes)
-AM_CONDITIONAL(QUOTA, test x$enable_quota = xyes)
+AM_CONDITIONAL(QUOTA, test x$enable_quota_module = xyes)
 AM_CONDITIONAL(SPLIT, test x$enable_split = xyes)
 AM_CONDITIONAL(BLKID, test x$ac_cv_header_blkid_blkid_h = xyes)
 AM_CONDITIONAL(EXT2FS_DEVEL, test x$ac_cv_header_ext2fs_ext2fs_h = xyes)
index d2c435d..839322a 100644 (file)
@@ -53,6 +53,9 @@
 #include <lustre_ver.h>
 #include "cmm_internal.h"
 #include "mdc_internal.h"
+#ifdef HAVE_QUOTA_SUPPORT
+# include <lustre_quota.h>
+#endif
 
 static struct obd_ops cmm_obd_device_ops = {
         .o_owner           = THIS_MODULE
@@ -127,12 +130,286 @@ static int cmm_update_capa_key(const struct lu_env *env,
         RETURN(rc);
 }
 
+#ifdef HAVE_QUOTA_SUPPORT
+static int cmm_quota_notify(const struct lu_env *env, struct md_device *m)
+{
+        struct cmm_device *cmm_dev = md2cmm_dev(m);
+        int rc;
+        ENTRY;
+
+        /* disable quota for CMD case temporary. */
+        if (cmm_dev->cmm_tgt_count)
+                RETURN(-EOPNOTSUPP);
+
+        rc = cmm_child_ops(cmm_dev)->mdo_quota.mqo_notify(env,
+                                                          cmm_dev->cmm_child);
+        RETURN(rc);
+}
+
+static int cmm_quota_setup(const struct lu_env *env, struct md_device *m,
+                           void *data)
+{
+        struct cmm_device *cmm_dev = md2cmm_dev(m);
+        int rc;
+        ENTRY;
+
+        /* disable quota for CMD case temporary. */
+        if (cmm_dev->cmm_tgt_count)
+                RETURN(-EOPNOTSUPP);
+
+        rc = cmm_child_ops(cmm_dev)->mdo_quota.mqo_setup(env,
+                                                         cmm_dev->cmm_child,
+                                                         data);
+        RETURN(rc);
+}
+
+static int cmm_quota_cleanup(const struct lu_env *env, struct md_device *m)
+{
+        struct cmm_device *cmm_dev = md2cmm_dev(m);
+        int rc;
+        ENTRY;
+
+        /* disable quota for CMD case temporary. */
+        if (cmm_dev->cmm_tgt_count)
+                RETURN(-EOPNOTSUPP);
+
+        rc = cmm_child_ops(cmm_dev)->mdo_quota.mqo_cleanup(env,
+                                                           cmm_dev->cmm_child);
+        RETURN(rc);
+}
+
+static int cmm_quota_recovery(const struct lu_env *env, struct md_device *m)
+{
+        struct cmm_device *cmm_dev = md2cmm_dev(m);
+        int rc;
+        ENTRY;
+
+        /* disable quota for CMD case temporary. */
+        if (cmm_dev->cmm_tgt_count)
+                RETURN(-EOPNOTSUPP);
+
+        rc = cmm_child_ops(cmm_dev)->mdo_quota.mqo_recovery(env,
+                                                            cmm_dev->cmm_child);
+        RETURN(rc);
+}
+
+static int cmm_quota_check(const struct lu_env *env, struct md_device *m,
+                           struct obd_export *exp, __u32 type)
+{
+        struct cmm_device *cmm_dev = md2cmm_dev(m);
+        int rc;
+        ENTRY;
+
+        /* disable quota for CMD case temporary. */
+        if (cmm_dev->cmm_tgt_count)
+                RETURN(-EOPNOTSUPP);
+
+        rc = cmm_child_ops(cmm_dev)->mdo_quota.mqo_check(env,
+                                                         cmm_dev->cmm_child,
+                                                         exp, type);
+        RETURN(rc);
+}
+
+static int cmm_quota_on(const struct lu_env *env, struct md_device *m,
+                        __u32 type, __u32 id)
+{
+        struct cmm_device *cmm_dev = md2cmm_dev(m);
+        int rc;
+        ENTRY;
+
+        /* disable quota for CMD case temporary. */
+        if (cmm_dev->cmm_tgt_count)
+                RETURN(-EOPNOTSUPP);
+
+        rc = cmm_child_ops(cmm_dev)->mdo_quota.mqo_on(env,
+                                                      cmm_dev->cmm_child,
+                                                      type, id);
+        RETURN(rc);
+}
+
+static int cmm_quota_off(const struct lu_env *env, struct md_device *m,
+                         __u32 type, __u32 id)
+{
+        struct cmm_device *cmm_dev = md2cmm_dev(m);
+        int rc;
+        ENTRY;
+
+        /* disable quota for CMD case temporary. */
+        if (cmm_dev->cmm_tgt_count)
+                RETURN(-EOPNOTSUPP);
+
+        rc = cmm_child_ops(cmm_dev)->mdo_quota.mqo_off(env,
+                                                       cmm_dev->cmm_child,
+                                                       type, id);
+        RETURN(rc);
+}
+
+static int cmm_quota_setinfo(const struct lu_env *env, struct md_device *m,
+                             __u32 type, __u32 id, struct obd_dqinfo *dqinfo)
+{
+        struct cmm_device *cmm_dev = md2cmm_dev(m);
+        int rc;
+        ENTRY;
+
+        /* disable quota for CMD case temporary. */
+        if (cmm_dev->cmm_tgt_count)
+                RETURN(-EOPNOTSUPP);
+
+        rc = cmm_child_ops(cmm_dev)->mdo_quota.mqo_setinfo(env,
+                                                           cmm_dev->cmm_child,
+                                                           type, id, dqinfo);
+        RETURN(rc);
+}
+
+static int cmm_quota_getinfo(const struct lu_env *env,
+                             const struct md_device *m,
+                             __u32 type, __u32 id, struct obd_dqinfo *dqinfo)
+{
+        struct cmm_device *cmm_dev = md2cmm_dev((struct md_device *)m);
+        int rc;
+        ENTRY;
+
+        /* disable quota for CMD case temporary. */
+        if (cmm_dev->cmm_tgt_count)
+                RETURN(-EOPNOTSUPP);
+
+        rc = cmm_child_ops(cmm_dev)->mdo_quota.mqo_getinfo(env,
+                                                           cmm_dev->cmm_child,
+                                                           type, id, dqinfo);
+        RETURN(rc);
+}
+
+static int cmm_quota_setquota(const struct lu_env *env, struct md_device *m,
+                              __u32 type, __u32 id, struct obd_dqblk *dqblk)
+{
+        struct cmm_device *cmm_dev = md2cmm_dev(m);
+        int rc;
+        ENTRY;
+
+        /* disable quota for CMD case temporary. */
+        if (cmm_dev->cmm_tgt_count)
+                RETURN(-EOPNOTSUPP);
+
+        rc = cmm_child_ops(cmm_dev)->mdo_quota.mqo_setquota(env,
+                                                            cmm_dev->cmm_child,
+                                                            type, id, dqblk);
+        RETURN(rc);
+}
+
+static int cmm_quota_getquota(const struct lu_env *env,
+                              const struct md_device *m,
+                              __u32 type, __u32 id, struct obd_dqblk *dqblk)
+{
+        struct cmm_device *cmm_dev = md2cmm_dev((struct md_device *)m);
+        int rc;
+        ENTRY;
+
+        /* disable quota for CMD case temporary. */
+        if (cmm_dev->cmm_tgt_count)
+                RETURN(-EOPNOTSUPP);
+
+        rc = cmm_child_ops(cmm_dev)->mdo_quota.mqo_getquota(env,
+                                                            cmm_dev->cmm_child,
+                                                            type, id, dqblk);
+        RETURN(rc);
+}
+
+static int cmm_quota_getoinfo(const struct lu_env *env,
+                              const struct md_device *m,
+                              __u32 type, __u32 id, struct obd_dqinfo *dqinfo)
+{
+        struct cmm_device *cmm_dev = md2cmm_dev((struct md_device *)m);
+        int rc;
+        ENTRY;
+
+        /* disable quota for CMD case temporary. */
+        if (cmm_dev->cmm_tgt_count)
+                RETURN(-EOPNOTSUPP);
+
+        rc = cmm_child_ops(cmm_dev)->mdo_quota.mqo_getoinfo(env,
+                                                            cmm_dev->cmm_child,
+                                                            type, id, dqinfo);
+        RETURN(rc);
+}
+
+static int cmm_quota_getoquota(const struct lu_env *env,
+                               const struct md_device *m,
+                               __u32 type, __u32 id, struct obd_dqblk *dqblk)
+{
+        struct cmm_device *cmm_dev = md2cmm_dev((struct md_device *)m);
+        int rc;
+        ENTRY;
+
+        /* disable quota for CMD case temporary. */
+        if (cmm_dev->cmm_tgt_count)
+                RETURN(-EOPNOTSUPP);
+
+        rc = cmm_child_ops(cmm_dev)->mdo_quota.mqo_getoquota(env,
+                                                             cmm_dev->cmm_child,
+                                                             type, id, dqblk);
+        RETURN(rc);
+}
+
+static int cmm_quota_invalidate(const struct lu_env *env, struct md_device *m,
+                                __u32 type)
+{
+        struct cmm_device *cmm_dev = md2cmm_dev(m);
+        int rc;
+        ENTRY;
+
+        /* disable quota for CMD case temporary. */
+        if (cmm_dev->cmm_tgt_count)
+                RETURN(-EOPNOTSUPP);
+
+        rc = cmm_child_ops(cmm_dev)->mdo_quota.mqo_invalidate(env,
+                                                              cmm_dev->cmm_child,
+                                                              type);
+        RETURN(rc);
+}
+
+static int cmm_quota_finvalidate(const struct lu_env *env, struct md_device *m,
+                                 __u32 type)
+{
+        struct cmm_device *cmm_dev = md2cmm_dev(m);
+        int rc;
+        ENTRY;
+
+        /* disable quota for CMD case temporary. */
+        if (cmm_dev->cmm_tgt_count)
+                RETURN(-EOPNOTSUPP);
+
+        rc = cmm_child_ops(cmm_dev)->mdo_quota.mqo_finvalidate(env,
+                                                               cmm_dev->cmm_child,
+                                                               type);
+        RETURN(rc);
+}
+#endif
+
 static const struct md_device_operations cmm_md_ops = {
         .mdo_statfs          = cmm_statfs,
         .mdo_root_get        = cmm_root_get,
         .mdo_maxsize_get     = cmm_maxsize_get,
         .mdo_init_capa_ctxt  = cmm_init_capa_ctxt,
         .mdo_update_capa_key = cmm_update_capa_key,
+#ifdef HAVE_QUOTA_SUPPORT
+        .mdo_quota           = {
+                .mqo_notify      = cmm_quota_notify,
+                .mqo_setup       = cmm_quota_setup,
+                .mqo_cleanup     = cmm_quota_cleanup,
+                .mqo_recovery    = cmm_quota_recovery,
+                .mqo_check       = cmm_quota_check,
+                .mqo_on          = cmm_quota_on,
+                .mqo_off         = cmm_quota_off,
+                .mqo_setinfo     = cmm_quota_setinfo,
+                .mqo_getinfo     = cmm_quota_getinfo,
+                .mqo_setquota    = cmm_quota_setquota,
+                .mqo_getquota    = cmm_quota_getquota,
+                .mqo_getoinfo    = cmm_quota_getoinfo,
+                .mqo_getoquota   = cmm_quota_getoquota,
+                .mqo_invalidate  = cmm_quota_invalidate,
+                .mqo_finvalidate = cmm_quota_finvalidate
+        }
+#endif
 };
 
 extern struct lu_device_type mdc_device_type;
index 3309687..73c9dad 100644 (file)
@@ -1274,5 +1274,5 @@ static const struct md_dir_operations cmr_dir_ops = {
         .mdo_link        = cmr_link,
         .mdo_unlink      = cmr_unlink,
         .mdo_rename      = cmr_rename,
-        .mdo_rename_tgt  = cmr_rename_tgt,
+        .mdo_rename_tgt  = cmr_rename_tgt
 };
index 5507962..db2d0b1 100644 (file)
@@ -146,7 +146,7 @@ static int mdc_obd_add(const struct lu_env *env,
                 ocd->ocd_ibits_known = MDS_INODELOCK_UPDATE;
                 ocd->ocd_connect_flags = OBD_CONNECT_VERSION |
                                          OBD_CONNECT_ACL |
-                                         OBD_CONNECT_LCL_CLIENT |
+                                         OBD_CONNECT_RMT_CLIENT |
                                          OBD_CONNECT_MDS_CAPA |
                                          OBD_CONNECT_OSS_CAPA |
                                          OBD_CONNECT_IBITS |
index 3b3b7fb..532a60b 100644 (file)
@@ -44,13 +44,33 @@ lfs \- Lustre utility to create a file with specific striping pattern, find the
 .br
 .B lfs quotaoff [-ug] <filesystem>
 .br
-.B lfs setquota [-u|-g] <username|groupname> <block-softlimit>
-             \fB<block-hardlimit> <inode-softlimit> <inode-hardlimit>
+.B lfs quotainv [-ug] [-f] <filesystem>
+.br
+.B lfs setquota [-u|--user|-g|--group] <username|groupname>
+             \fB[--block-softlimit <block-softlimit>]
+             \fB[--block-hardlimit <block-hardlimit>]
+             \fB[--inode-softlimit <inode-softlimit>]
+             \fB[--inode-hardlimit <inode-hardlimit>]
              \fB<filesystem>\fR
 .br
-.B lfs setquota -t [-u|-g] <block-grace> <inode-grace> <filesystem>
+.B lfs setquota [-u|--user|-g|--group] <username|groupname>
+             \fB[-b <block-softlimit>] [-B <block-hardlimit>]
+             \fB[-i <inode-softlimit>] [-I <inode-hardlimit>]
+             \fB<filesystem>\fR
 .br
-.B lfs quota [-o obd_uuid] [-u|-g] <username|groupname> <filesystem>
+.B lfs setquota -t [-u|-g]
+             \fB[--block-grace <block-grace>]
+             \fB[--inode-grace <inode-grace>]
+             \fB<filesystem>\fR
+.br
+.B lfs setquota -t [-u|-g]
+             \fB[-b <block-grace>] [-i <inode-grace>]
+             \fB<filesystem>\fR
+.br
+
+.B lfs quota [-v] [-o obd_uuid|-i mdt_idx|-I ost_idx] [-u|-g] <username|groupname> <filesystem>
+.br
+.B lfs quota <filesystem>
 .br
 .B lfs quota -t [-u|-g] <filesystem>
 .br
@@ -121,14 +141,17 @@ 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 setquota  [-u|-g] <name> <block-softlimit> <block-hardlimit> <inode-softlimit> <inode-hardlimit> <filesystem>
-To set filesystem quotas for users or groups. Limits are specific as blocks and inodes, see EXAMPLES
+.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
 .TP
-.B setquota -t [-u|-g] <block-grace> <inode-grace> <filesystem>
+.B setquota -t [-u|-g] [--block-grace <block-grace>] [--inode-grace <inode-grace>] <filesystem>
 To set filesystem quota grace times for users or groups. Grace time is specified in "XXwXXdXXhXXmXXs" format or as an integer seconds value, see EXAMPLES
 .TP
-.B quota [-o obd_uuid] [-u|-g] <username|groupname> <filesystem>
-To display disk usage and limits, either for the full filesystem, or for objects on a specific obd. A user or group name must be specified.
+.B quota [-v] [-o obd_uuid|-i mdt_idx|-I ost_idx] [-u|-g] <username|groupname> <filesystem>
+To display disk usage and limits, either for the full filesystem, or for objects on a specific obd. A user or group name can be specified. If both user and group are omitted quotas for current uid/gid are shown. -v provides more verbose (with per-obd statistics) output.
 .TP
 .B quota -t [-u|-g] <filesystem>
 To display block and inode grace times for user (-u) or group (-g) quotas
@@ -141,7 +164,7 @@ Quit the interactive lfs session
 .SH EXAMPLES
 .TP
 .B $ lfs setstripe -s 128k -c 2 /mnt/lustre/file1
-This creats a file striped on two OSTs with 128kB on each stripe.
+This creates a file striped on two OSTs with 128kB on each stripe.
 .TP
 .B $ lfs setstripe -d /mnt/lustre/dir
 This deletes a default stripe pattern on dir. New files will use the default striping pattern created therein.
@@ -182,10 +205,10 @@ Turn quotas of user and group on
 .B $ lfs quotaoff -ug /mnt/lustre
 Turn quotas of user and group off
 .TP
-.B $ lfs setquota -u bob 0 1000000 0 10000 /mnt/lustre
-Set quotas of user `bob': 1GB block quota and 10,000 file quota
+.B $ lfs setquota -u bob --block-softlimit 2000000 --block-hardlimit 1000000 /mnt/lustre
+Set quotas of user `bob': 1GB block quota hardlimit and 2 GB block quota softlimit
 .TP
-.B $ lfs setquota -t -u 1000 1w4d /mnt/lustre
+.B $ lfs setquota -t -u --block-grace 1000 --inode-grace 1w4d /mnt/lustre
 Set grace times for user quotas: 1000 seconds for block quotas, 1 week and 4 days for inode quotas
 .TP
 .B $ lfs quota -u bob /mnt/lustre
index 42fda49..7a827da 100644 (file)
@@ -102,7 +102,7 @@ int seq_store_write(struct lu_server_seq *seq,
 
                 rc = dt_obj->do_body_ops->dbo_write(env, dt_obj,
                                                     seq_store_buf(info),
-                                                    &pos, th, BYPASS_CAPA);
+                                                    &pos, th, BYPASS_CAPA, 1);
                 if (rc == sizeof(info->sti_space)) {
                         CDEBUG(D_INFO, "%s: Space - "DRANGE"\n",
                                seq->lss_name, PRANGE(&seq->lss_space));
index a1e88d4..aba0bb0 100644 (file)
@@ -131,7 +131,7 @@ int fld_index_create(struct lu_server_fld *fld,
                 rc = dt_obj->do_index_ops->dio_insert(env, dt_obj,
                                                       fld_rec(env, mds),
                                                       fld_key(env, seq),
-                                                      th, BYPASS_CAPA);
+                                                      th, BYPASS_CAPA, 1);
                 dt_dev->dd_ops->dt_trans_stop(env, th);
         } else
                 rc = PTR_ERR(th);
index e2b2b11..6210c7f 100644 (file)
@@ -170,7 +170,7 @@ __lustre_hash_key_validate(lustre_hash_t *lh, void *key,
                            struct hlist_node *hnode)
 {
         if (unlikely(lh->lh_flags & LH_DEBUG))
-                LASSERT(lh_compare(lh, key, hnode));
+                LASSERT(lh_compare(lh, key, hnode) > 0);
 }
 
 /* Validate hnode is in the correct bucket */
@@ -193,7 +193,7 @@ __lustre_hash_bucket_lookup(lustre_hash_t *lh,
         struct hlist_node *hnode;
 
         hlist_for_each(hnode, &lhb->lhb_head)
-                if (lh_compare(lh, key, hnode))
+                if (lh_compare(lh, key, hnode) > 0)
                         return hnode;
 
         return NULL;
index fbbb9ad..0cd80c4 100644 (file)
@@ -66,6 +66,7 @@ struct txn_param;
 struct dt_device;
 struct dt_object;
 struct dt_index_features;
+struct dt_quota_ctxt;
 
 struct dt_device_param {
         unsigned           ddp_max_name_len;
@@ -82,11 +83,12 @@ enum dt_txn_op {
         DTO_IDNEX_UPDATE,
         DTO_OBJECT_CREATE,
         DTO_OBJECT_DELETE,
-        DTO_ATTR_SET,
+        DTO_ATTR_SET_BASE,
         DTO_XATTR_SET,
         DTO_LOG_REC, /**< XXX temporary: dt layer knows nothing about llog. */
         DTO_WRITE_BASE,
         DTO_WRITE_BLOCK,
+        DTO_ATTR_SET_CHOWN,
 
         DTO_NR
 };
@@ -144,6 +146,12 @@ struct dt_device_operations {
                                    struct dt_device *dev,
                                    int mode, unsigned long timeout,
                                    __u32 alg, struct lustre_capa_key *keys);
+        /**
+         * Initialize quota context.
+         */
+        void (*dt_init_quota_ctxt)(const struct lu_env *env,
+                                   struct dt_device *dev,
+                                   struct dt_quota_ctxt *ctxt, void *data);
 
         /**
          *  get transaction credits for given \a op.
@@ -337,7 +345,8 @@ struct dt_body_operations {
          */
         ssize_t (*dbo_write)(const struct lu_env *env, struct dt_object *dt,
                              const struct lu_buf *buf, loff_t *pos,
-                             struct thandle *handle, struct lustre_capa *capa);
+                             struct thandle *handle, struct lustre_capa *capa,
+                             int ignore_quota);
 };
 
 /**
@@ -370,7 +379,8 @@ struct dt_index_operations {
          */
         int (*dio_insert)(const struct lu_env *env, struct dt_object *dt,
                           const struct dt_rec *rec, const struct dt_key *key,
-                          struct thandle *handle, struct lustre_capa *capa);
+                          struct thandle *handle, struct lustre_capa *capa,
+                          int ignore_quota);
         /**
          * precondition: dt_object_exists(dt);
          */
index 713341e..cfdc247 100644 (file)
@@ -43,7 +43,7 @@
 #define _LUSTRE_LINUX_ACL_H
 
 #ifndef        _LUSTRE_ACL_H
-#error Shoud not include direectly. use #include <lustre/lustre_acl.h> instead
+#error Shoud not include direectly. use #include <lustre_acl.h> instead
 #endif
 
 #ifdef __KERNEL__
index 7f3f0da..13c0385 100644 (file)
@@ -501,9 +501,32 @@ struct blkcipher_desc {
 #define ll_crypto_blkcipher_encrypt_iv(desc, dst, src, bytes) \
         crypto_cipher_encrypt_iv((desc)->tfm, dst, src, bytes, (desc)->info)
 
-extern struct ll_crypto_cipher *ll_crypto_alloc_blkcipher(
-                            const char * algname, u32 type, u32 mask);
 static inline
+struct ll_crypto_cipher *ll_crypto_alloc_blkcipher(const char * algname,
+                                                   u32 type, u32 mask)
+{
+        char        buf[CRYPTO_MAX_ALG_NAME + 1];
+        const char *pan = algname;
+        u32         flag = 0; 
+
+        if (strncmp("cbc(", algname, 4) == 0)
+                flag |= CRYPTO_TFM_MODE_CBC;
+        else if (strncmp("ecb(", algname, 4) == 0)
+                flag |= CRYPTO_TFM_MODE_ECB;
+        if (flag) {
+                char *vp = strnchr(algname, CRYPTO_MAX_ALG_NAME, ')');
+                if (vp) {
+                        memcpy(buf, algname + 4, vp - algname - 4);
+                        buf[vp - algname - 4] = '\0';
+                        pan = buf;
+                } else {
+                        flag = 0;
+                }
+        }
+        return crypto_alloc_tfm(pan, flag);
+}
+
+static inline 
 struct ll_crypto_hash *ll_crypto_alloc_hash(const char *alg, u32 type, u32 mask)
 {
         char        buf[CRYPTO_MAX_ALG_NAME + 1];
index 2996e36..b544341 100644 (file)
@@ -113,12 +113,12 @@ struct fsfilt_operations {
         int     (* fs_read_record)(struct file *, void *, int size, loff_t *);
         int     (* fs_setup)(struct super_block *sb);
         int     (* fs_get_op_len)(int, struct fsfilt_objinfo *, int);
-        int     (* fs_quotactl)(struct super_block *sb,
-                                struct obd_quotactl *oqctl);
         int     (* fs_quotacheck)(struct super_block *sb,
                                   struct obd_quotactl *oqctl);
         __u64   (* fs_get_version) (struct inode *inode);
         __u64   (* fs_set_version) (struct inode *inode, __u64 new_version);
+        int     (* fs_quotactl)(struct super_block *sb,
+                                struct obd_quotactl *oqctl);
         int     (* fs_quotainfo)(struct lustre_quota_info *lqi, int type,
                                  int cmd);
         int     (* fs_qids)(struct file *file, struct inode *inode, int type,
@@ -167,18 +167,21 @@ static inline lvfs_sbdev_type fsfilt_journal_sbdev(struct obd_device *obd,
         return (lvfs_sbdev_type)0;
 }
 
-#define FSFILT_OP_UNLINK         1
-#define FSFILT_OP_RMDIR          2
-#define FSFILT_OP_RENAME         3
-#define FSFILT_OP_CREATE         4
-#define FSFILT_OP_MKDIR          5
-#define FSFILT_OP_SYMLINK        6
-#define FSFILT_OP_MKNOD          7
-#define FSFILT_OP_SETATTR        8
-#define FSFILT_OP_LINK           9
-#define FSFILT_OP_CANCEL_UNLINK 10
-#define FSFILT_OP_JOIN          11
-#define FSFILT_OP_NOOP          15
+#define FSFILT_OP_UNLINK                1
+#define FSFILT_OP_RMDIR                 2
+#define FSFILT_OP_RENAME                3
+#define FSFILT_OP_CREATE                4
+#define FSFILT_OP_MKDIR                 5
+#define FSFILT_OP_SYMLINK               6
+#define FSFILT_OP_MKNOD                 7
+#define FSFILT_OP_SETATTR               8
+#define FSFILT_OP_LINK                  9
+#define FSFILT_OP_CANCEL_UNLINK         10
+#define FSFILT_OP_JOIN                  11
+#define FSFILT_OP_NOOP                  15
+#define FSFILT_OP_UNLINK_PARTIAL_CHILD  21
+#define FSFILT_OP_UNLINK_PARTIAL_PARENT 22
+#define FSFILT_OP_CREATE_PARTIAL_CHILD  23
 
 #define __fsfilt_check_slow(obd, start, msg)                            \
 do {                                                                    \
index b44679e..da302bc 100644 (file)
@@ -48,6 +48,9 @@
 # endif
 #else
 # include <linux/version.h>
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,21)
+#  define NEED_QUOTA_DEFS
+# endif
 # ifdef HAVE_QUOTA_SUPPORT
 #  include <linux/quota.h>
 # endif
index 8ef613e..7763498 100644 (file)
@@ -222,7 +222,7 @@ static inline int opcode_offset(__u32 opc) {
                         (LDLM_LAST_OPC - LDLM_FIRST_OPC) +
                         (MDS_LAST_OPC - MDS_FIRST_OPC) +
                         (OST_LAST_OPC - OST_FIRST_OPC));
-} else if (opc < FLD_LAST_OPC) {
+        } else if (opc < FLD_LAST_OPC) {
                 /* FLD opcode */
                 return (opc - FLD_FIRST_OPC +
                         (LLOG_LAST_OPC - LLOG_FIRST_OPC) +
@@ -252,6 +252,18 @@ static inline int opcode_offset(__u32 opc) {
                         (LDLM_LAST_OPC - LDLM_FIRST_OPC) +
                         (MDS_LAST_OPC - MDS_FIRST_OPC) +
                         (OST_LAST_OPC - OST_FIRST_OPC));
+        } else if (opc < QUOTA_LAST_OPC) {
+                /* LQUOTA Opcode */
+                return (opc - QUOTA_FIRST_OPC +
+                        (SEC_LAST_OPC - SEC_FIRST_OPC) +
+                        (SEQ_LAST_OPC - SEQ_FIRST_OPC) +
+                        (FLD_LAST_OPC - FLD_FIRST_OPC) +
+                        (LLOG_LAST_OPC - LLOG_FIRST_OPC) +
+                        (OBD_LAST_OPC - OBD_FIRST_OPC) +
+                        (MGS_LAST_OPC - MGS_FIRST_OPC) +
+                        (LDLM_LAST_OPC - LDLM_FIRST_OPC) +
+                        (MDS_LAST_OPC - MDS_FIRST_OPC) +
+                        (OST_LAST_OPC - OST_FIRST_OPC));
         } else {
                 /* Unknown Opcode */
                 return -1;
@@ -266,7 +278,8 @@ static inline int opcode_offset(__u32 opc) {
                             (SEQ_LAST_OPC - SEQ_FIRST_OPC)     + \
                             (MGS_LAST_OPC - MGS_FIRST_OPC)     + \
                             (LLOG_LAST_OPC - LLOG_FIRST_OPC)   + \
-                            (SEC_LAST_OPC - SEC_FIRST_OPC))
+                            (SEC_LAST_OPC - SEC_FIRST_OPC)     + \
+                            (QUOTA_LAST_OPC - QUOTA_FIRST_OPC))
 
 #define EXTRA_MAX_OPCODES ((PTLRPC_LAST_CNTR - PTLRPC_FIRST_CNTR)  + \
                            (EXTRA_LAST_OPC - EXTRA_FIRST_OPC))
@@ -288,12 +301,13 @@ enum {
         LDLM_EXTENT_ENQUEUE,
         LDLM_FLOCK_ENQUEUE,
         LDLM_IBITS_ENQUEUE,
+        MDS_REINT_SETATTR,
         MDS_REINT_CREATE,
         MDS_REINT_LINK,
-        MDS_REINT_OPEN,
-        MDS_REINT_SETATTR,
-        MDS_REINT_RENAME,
         MDS_REINT_UNLINK,
+        MDS_REINT_RENAME,
+        MDS_REINT_OPEN,
+        MDS_REINT_SETXATTR,
         BRW_READ_BYTES,
         BRW_WRITE_BYTES,
         EXTRA_LAST_OPC
@@ -617,6 +631,56 @@ int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
 /* lprocfs_status.c: write recovery max time bz13079 */
 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
                                     unsigned long count, void *data);
+
+/* all quota proc functions */
+extern int lprocfs_quota_rd_bunit(char *page, char **start, off_t off, int count,
+                                  int *eof, void *data);
+extern int lprocfs_quota_wr_bunit(struct file *file, const char *buffer,
+                                  unsigned long count, void *data);
+extern int lprocfs_quota_rd_btune(char *page, char **start, off_t off, int count,
+                                  int *eof, void *data);
+extern int lprocfs_quota_wr_btune(struct file *file, const char *buffer,
+                                  unsigned long count, void *data);
+extern int lprocfs_quota_rd_iunit(char *page, char **start, off_t off, int count,
+                                  int *eof, void *data);
+extern int lprocfs_quota_wr_iunit(struct file *file, const char *buffer,
+                                  unsigned long count, void *data);
+extern int lprocfs_quota_rd_itune(char *page, char **start, off_t off, int count,
+                                  int *eof, void *data);
+extern int lprocfs_quota_wr_itune(struct file *file, const char *buffer,
+                                  unsigned long count, void *data);
+extern int lprocfs_quota_rd_type(char *page, char **start, off_t off, int count,
+                                 int *eof, void *data);
+extern int lprocfs_quota_wr_type(struct file *file, const char *buffer,
+                                 unsigned long count, void *data);
+extern int lprocfs_quota_rd_switch_seconds(char *page, char **start, off_t off,
+                                           int count, int *eof, void *data);
+extern int lprocfs_quota_wr_switch_seconds(struct file *file, const char *buffer,
+                                           unsigned long count, void *data);
+extern int lprocfs_quota_rd_sync_blk(char *page, char **start, off_t off,
+                                     int count, int *eof, void *data);
+extern int lprocfs_quota_wr_sync_blk(struct file *file, const char *buffer,
+                                     unsigned long count, void *data);
+extern int lprocfs_quota_rd_switch_qs(char *page, char **start, off_t off,
+                                      int count, int *eof, void *data);
+extern int lprocfs_quota_wr_switch_qs(struct file *file, const char *buffer,
+                                      unsigned long count, void *data);
+extern int lprocfs_quota_rd_boundary_factor(char *page, char **start, off_t off,
+                                            int count, int *eof, void *data);
+extern int lprocfs_quota_wr_boundary_factor(struct file *file, const char *buffer,
+                                            unsigned long count, void *data);
+extern int lprocfs_quota_rd_least_bunit(char *page, char **start, off_t off,
+                                        int count, int *eof, void *data);
+extern int lprocfs_quota_wr_least_bunit(struct file *file, const char *buffer,
+                                        unsigned long count, void *data);
+extern int lprocfs_quota_rd_least_iunit(char *page, char **start, off_t off,
+                                        int count, int *eof, void *data);
+extern int lprocfs_quota_wr_least_iunit(struct file *file, const char *buffer,
+                                        unsigned long count, void *data);
+extern int lprocfs_quota_rd_qs_factor(char *page, char **start, off_t off,
+                                      int count, int *eof, void *data);
+extern int lprocfs_quota_wr_qs_factor(struct file *file, const char *buffer,
+                                      unsigned long count, void *data);
 #else
 /* LPROCFS is not defined */
 static inline void lprocfs_counter_add(struct lprocfs_stats *stats,
@@ -651,7 +715,7 @@ static inline void lprocfs_init_ops_stats(int num_private_stats,
 static inline void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
 { return; }
 static inline int lprocfs_alloc_obd_stats(struct obd_device *obddev,
-                                             unsigned int num_private_stats)
+                                          unsigned int num_private_stats)
 { return 0; }
 static inline int lprocfs_alloc_md_stats(struct obd_device *obddev,
                                          unsigned int num_private_stats)
@@ -663,7 +727,7 @@ struct obd_export;
 static inline int lprocfs_add_clear_entry(struct obd_export *exp)
 { return 0; }
 static inline int lprocfs_exp_setup(struct obd_export *exp,
-                                   lnet_nid_t *peer_nid, int *newnid)
+                                    lnet_nid_t *peer_nid, int *newnid)
 { return 0; }
 static inline int lprocfs_exp_cleanup(struct obd_export *exp)
 { return 0; }
index 8717532..3f4fd1e 100644 (file)
@@ -84,7 +84,7 @@ extern int llapi_poollist(char *name);
 extern int llapi_file_get_stripe(const char *path, struct lov_user_md *lum);
 #define HAVE_LLAPI_FILE_LOOKUP
 extern int llapi_file_lookup(int dirfd, const char *name);
+
 struct find_param {
         unsigned int maxdepth;
         time_t  atime;
@@ -151,8 +151,9 @@ extern int llapi_file_get_lov_uuid(const char *path, struct obd_uuid *lov_uuid);
 extern int llapi_file_fget_lov_uuid(int fd, struct obd_uuid *lov_uuid);
 extern int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count);
 extern int llapi_is_lustre_mnttype(const char *type);
+extern int llapi_get_obd_count(char *mnt, int *count, int is_mdt);
 extern int parse_size(char *optarg, unsigned long long *size,
-                      unsigned long long *size_units);
+                      unsigned long long *size_units, int bytes_spec);
 extern int llapi_path2fid(const char *path, unsigned long long *seq,
                           unsigned long *oid, unsigned long *ver);
 
index fbb1af2..81fd3b7 100644 (file)
@@ -653,8 +653,8 @@ extern void lustre_swab_ptlrpc_body(struct ptlrpc_body *pb);
 #define OBD_CONNECT_JOIN       0x00002000ULL /* files can be concatenated */
 #define OBD_CONNECT_ATTRFID    0x00004000ULL /* Server supports GetAttr By Fid */
 #define OBD_CONNECT_NODEVOH    0x00008000ULL /* No open handle for special nodes */
-#define OBD_CONNECT_LCL_CLIENT 0x00010000ULL /* local 1.8 client */
-#define OBD_CONNECT_RMT_CLIENT 0x00020000ULL /* Remote 1.8 client */
+#define OBD_CONNECT_RMT_CLIENT 0x00010000ULL /* Remote client */
+#define OBD_CONNECT_RMT_CLIENT_FORCE 0x00020000ULL /* Remote client by force */
 #define OBD_CONNECT_BRW_SIZE   0x00040000ULL /* Max bytes per rpc */
 #define OBD_CONNECT_QUOTA64    0x00080000ULL /* 64bit qunit_data.qd_count b=10707*/
 #define OBD_CONNECT_MDS_CAPA   0x00100000ULL /* MDS capability */
@@ -683,8 +683,8 @@ extern void lustre_swab_ptlrpc_body(struct ptlrpc_body *pb);
                                 OBD_CONNECT_ACL | OBD_CONNECT_XATTR | \
                                 OBD_CONNECT_IBITS | OBD_CONNECT_JOIN | \
                                 OBD_CONNECT_NODEVOH |/* OBD_CONNECT_ATTRFID |*/\
-                                OBD_CONNECT_LCL_CLIENT | \
                                 OBD_CONNECT_RMT_CLIENT | \
+                                OBD_CONNECT_RMT_CLIENT_FORCE | \
                                 OBD_CONNECT_MDS_CAPA | OBD_CONNECT_OSS_CAPA | \
                                 OBD_CONNECT_MDS_MDS | OBD_CONNECT_CANCELSET | \
                                 OBD_CONNECT_FID | \
@@ -696,7 +696,9 @@ extern void lustre_swab_ptlrpc_body(struct ptlrpc_body *pb);
                                 OBD_CONNECT_BRW_SIZE | OBD_CONNECT_QUOTA64 | \
                                 OBD_CONNECT_OSS_CAPA | OBD_CONNECT_CANCELSET | \
                                 OBD_CONNECT_CKSUM | LRU_RESIZE_CONNECT_FLAG | \
-                                OBD_CONNECT_AT)
+                                OBD_CONNECT_AT | OBD_CONNECT_CHANGE_QS | \
+                                OBD_CONNECT_RMT_CLIENT | \
+                                OBD_CONNECT_RMT_CLIENT_FORCE)
 #define ECHO_CONNECT_SUPPORTED (0)
 #define MGS_CONNECT_SUPPORTED  (OBD_CONNECT_VERSION | OBD_CONNECT_AT)
 
@@ -766,6 +768,7 @@ typedef enum {
         OST_SET_INFO   = 17,
         OST_QUOTACHECK = 18,
         OST_QUOTACTL   = 19,
+        OST_QUOTA_ADJUST_QUNIT = 20,
         OST_LAST_OPC
 } ost_cmd_t;
 #define OST_FIRST_OPC  OST_REPLY
@@ -908,6 +911,8 @@ struct lov_mds_md_v3 {            /* LOV EA mds/wire data (little-endian) */
 #define OBD_MD_FLCKSPLIT   (0x0000080000000000ULL) /* Check split on server */
 #define OBD_MD_FLCROSSREF  (0x0000100000000000ULL) /* Cross-ref case */
 
+#define OBD_FL_TRUNC       (0x0000200000000000ULL) /* for filter_truncate */
+
 #define OBD_MD_FLRMTLSETFACL    (0x0001000000000000ULL) /* lfs lsetfacl case */
 #define OBD_MD_FLRMTLGETFACL    (0x0002000000000000ULL) /* lfs lgetfacl case */
 #define OBD_MD_FLRMTRSETFACL    (0x0004000000000000ULL) /* lfs rsetfacl case */
@@ -1244,13 +1249,26 @@ extern void lustre_swab_mdt_epoch (struct mdt_epoch *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_TYPEMATCH(id, type) \
+        ((id) == (type) || (id) == UGQUOTA)
 
-#define Q_TYPESET(oqc, type) \
-        ((oqc)->qc_type == type || (oqc)->qc_type == 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)
 
+#define QCTL_COPY(out, in)              \
+do {                                    \
+        Q_COPY(out, in, qc_cmd);        \
+        Q_COPY(out, in, qc_type);       \
+        Q_COPY(out, in, qc_id);         \
+        Q_COPY(out, in, qc_stat);       \
+        Q_COPY(out, in, qc_dqinfo);     \
+        Q_COPY(out, in, qc_dqblk);      \
+} while (0)
+
 struct obd_quotactl {
         __u32                   qc_cmd;
         __u32                   qc_type;
@@ -1262,6 +1280,34 @@ struct obd_quotactl {
 
 extern void lustre_swab_obd_quotactl(struct obd_quotactl *q);
 
+struct quota_adjust_qunit {
+        __u32 qaq_flags;
+        __u32 qaq_id;
+        __u64 qaq_bunit_sz;
+        __u64 qaq_iunit_sz;
+        __u64 padding1;
+};
+extern void lustre_swab_quota_adjust_qunit(struct quota_adjust_qunit *q);
+
+/* flags in qunit_data and quota_adjust_qunit will use macroes below */
+#define LQUOTA_FLAGS_GRP       1UL   /* 0 is user, 1 is group */
+#define LQUOTA_FLAGS_BLK       2UL   /* 0 is inode, 1 is block */
+#define LQUOTA_FLAGS_ADJBLK    4UL   /* adjust the block qunit size */
+#define LQUOTA_FLAGS_ADJINO    8UL   /* adjust the inode qunit size */
+#define LQUOTA_FLAGS_CHG_QS   16UL   /* indicate whether it has capability of
+                                      * OBD_CONNECT_CHANGE_QS */
+
+/* the status of lqsk_flags in struct lustre_qunit_size_key */
+#define LQUOTA_QUNIT_FLAGS (LQUOTA_FLAGS_GRP | LQUOTA_FLAGS_BLK)
+
+#define QAQ_IS_GRP(qaq)    ((qaq)->qaq_flags & LQUOTA_FLAGS_GRP)
+#define QAQ_IS_ADJBLK(qaq) ((qaq)->qaq_flags & LQUOTA_FLAGS_ADJBLK)
+#define QAQ_IS_ADJINO(qaq) ((qaq)->qaq_flags & LQUOTA_FLAGS_ADJINO)
+
+#define QAQ_SET_GRP(qaq)    ((qaq)->qaq_flags |= LQUOTA_FLAGS_GRP)
+#define QAQ_SET_ADJBLK(qaq) ((qaq)->qaq_flags |= LQUOTA_FLAGS_ADJBLK)
+#define QAQ_SET_ADJINO(qaq) ((qaq)->qaq_flags |= LQUOTA_FLAGS_ADJINO)
+
 /* inode access permission for remote user, the inode info are omitted,
  * for client knows them. */
 struct mds_remote_perm {
@@ -1277,7 +1323,8 @@ enum {
         CFS_SETUID_PERM = 0x01,
         CFS_SETGID_PERM = 0x02,
         CFS_SETGRP_PERM = 0x04,
-        CFS_RMTACL_PERM = 0x08
+        CFS_RMTACL_PERM = 0x08,
+        CFS_RMTOWN_PERM = 0x10
 };
 
 extern void lustre_swab_mds_remote_perm(struct mds_remote_perm *p);
@@ -1421,7 +1468,8 @@ enum {
         MDS_CROSS_REF    = 1 << 1,
         MDS_VTX_BYPASS   = 1 << 2,
         MDS_PERM_BYPASS  = 1 << 3,
-        MDS_SOM          = 1 << 4
+        MDS_SOM          = 1 << 4,
+        MDS_QUOTA_IGNORE = 1 << 5
 };
 
 struct mds_rec_join {
@@ -2261,7 +2309,6 @@ struct obdo {
 extern void lustre_swab_obdo (struct obdo *o);
 
 /* request structure for OST's */
-
 struct ost_body {
         struct  obdo oa;
 };
@@ -2293,37 +2340,71 @@ extern void lustre_swab_llog_rec(struct llog_rec_hdr  *rec,
 struct lustre_cfg;
 extern void lustre_swab_lustre_cfg(struct lustre_cfg *lcfg);
 
-/* quota. fixed by tianzy for bug10707 */
-#define QUOTA_IS_GRP   0X1UL  /* 0 is user, 1 is group. Used by qd_flags*/
-#define QUOTA_IS_BLOCK 0x2UL  /* 0 is inode, 1 is block. Used by qd_flags*/
-
+/* this will be used when OBD_CONNECT_CHANGE_QS is set */
 struct qunit_data {
-        __u32 qd_id; /* ID appiles to (uid, gid) */
-        __u32 qd_flags; /* Quota type (USRQUOTA, GRPQUOTA) occupy one bit;
-                         * Block quota or file quota occupy one bit */
-        __u64 qd_count; /* acquire/release count (bytes for block quota) */
+        /**
+         * ID appiles to (uid, gid)
+         */
+        __u32 qd_id;
+        /**
+         * LQUOTA_FLAGS_* affect the responding bits
+         */
+        __u32 qd_flags;
+        /**
+         * acquire/release count (bytes for block quota)
+         */
+        __u64 qd_count;
+        /**
+         * when a master returns the reply to a slave, it will
+         * contain the current corresponding qunit size
+         */
+        __u64 qd_qunit;
+        __u64 padding;
 };
 
-struct qunit_data_old {
-        __u32 qd_id;    /* ID appiles to (uid, gid) */
-        __u32 qd_type;  /* Quota type (USRQUOTA, GRPQUOTA) */
-        __u32 qd_count; /* acquire/release count (bytes for block quota) */
-        __u32 qd_isblk; /* Block quota or file quota */
-};
+#define QDATA_IS_GRP(qdata)    ((qdata)->qd_flags & LQUOTA_FLAGS_GRP)
+#define QDATA_IS_BLK(qdata)    ((qdata)->qd_flags & LQUOTA_FLAGS_BLK)
+#define QDATA_IS_ADJBLK(qdata) ((qdata)->qd_flags & LQUOTA_FLAGS_ADJBLK)
+#define QDATA_IS_ADJINO(qdata) ((qdata)->qd_flags & LQUOTA_FLAGS_ADJINO)
+#define QDATA_IS_CHANGE_QS(qdata) ((qdata)->qd_flags & LQUOTA_FLAGS_CHG_QS)
+
+#define QDATA_SET_GRP(qdata)    ((qdata)->qd_flags |= LQUOTA_FLAGS_GRP)
+#define QDATA_SET_BLK(qdata)    ((qdata)->qd_flags |= LQUOTA_FLAGS_BLK)
+#define QDATA_SET_ADJBLK(qdata) ((qdata)->qd_flags |= LQUOTA_FLAGS_ADJBLK)
+#define QDATA_SET_ADJINO(qdata) ((qdata)->qd_flags |= LQUOTA_FLAGS_ADJINO)
+#define QDATA_SET_CHANGE_QS(qdata) ((qdata)->qd_flags |= LQUOTA_FLAGS_CHG_QS)
+
+#define QDATA_CLR_GRP(qdata)        ((qdata)->qd_flags &= ~LQUOTA_FLAGS_GRP)
+#define QDATA_CLR_CHANGE_QS(qdata)  ((qdata)->qd_flags &= ~LQUOTA_FLAGS_CHG_QS)
 
 extern void lustre_swab_qdata(struct qunit_data *d);
-extern void lustre_swab_qdata_old(struct qunit_data_old *d);
-extern struct qunit_data *lustre_quota_old_to_new(struct qunit_data_old *d);
-extern struct qunit_data_old *lustre_quota_new_to_old(struct qunit_data *d);
+extern int quota_get_qdata(void*req, struct qunit_data *qdata,
+                           int is_req, int is_exp);
+extern int quota_copy_qdata(void *request, struct qunit_data *qdata,
+                            int is_req, int is_exp);
 
 typedef enum {
-        QUOTA_DQACQ     = 601,
-        QUOTA_DQREL     = 602,
+        QUOTA_DQACQ     = 901,
+        QUOTA_DQREL     = 902,
+        QUOTA_LAST_OPC
 } quota_cmd_t;
+#define QUOTA_FIRST_OPC QUOTA_DQACQ
 
 #define JOIN_FILE_ALIGN 4096
 
-/** security opcodes */
+#define QUOTA_REQUEST   1
+#define QUOTA_REPLY     0
+#define QUOTA_EXPORT    1
+#define QUOTA_IMPORT    0
+
+/* quota check function */
+#define QUOTA_RET_OK           0 /**< return successfully */
+#define QUOTA_RET_NOQUOTA      1 /**< not support quota */
+#define QUOTA_RET_NOLIMIT      2 /**< quota limit isn't set */
+#define QUOTA_RET_ACQUOTA      4 /**< need to acquire extra quota */
+#define QUOTA_RET_INC_PENDING  8 /**< pending value is increased */
+
+/* security opcodes */
 typedef enum {
         SEC_CTX_INIT            = 801,
         SEC_CTX_INIT_CONT       = 802,
@@ -2341,15 +2422,15 @@ typedef enum {
 /* NB take care when changing the sequence of elements this struct,
  * because the offset info is used in find_capa() */
 struct lustre_capa {
-        struct lu_fid   lc_fid;     /* fid */
-        __u64           lc_opc;     /* operations allowed */
-        __u32           lc_uid;     /* uid, it is obsolete, but maybe used in
-                                     * future, reserve it for 64-bits aligned.*/
-        __u32           lc_flags;   /* HMAC algorithm & flags */
-        __u32           lc_keyid;   /* key used for the capability */
-        __u32           lc_timeout; /* capa timeout value (sec) */
-        __u64           lc_expiry;  /* expiry time (sec) */
-        __u8            lc_hmac[CAPA_HMAC_MAX_LEN];   /* HMAC */
+        struct lu_fid   lc_fid;         /** fid */
+        __u64           lc_opc;         /** operations allowed */
+        __u64           lc_uid;         /** file owner */
+        __u64           lc_gid;         /** file group */
+        __u32           lc_flags;       /** HMAC algorithm & flags */
+        __u32           lc_keyid;       /** key# used for the capability */
+        __u32           lc_timeout;     /** capa timeout value (sec) */
+        __u32           lc_expiry;      /** expiry time (sec) */
+        __u8            lc_hmac[CAPA_HMAC_MAX_LEN];   /** HMAC */
 } __attribute__((packed));
 
 extern void lustre_swab_lustre_capa(struct lustre_capa *c);
@@ -2364,9 +2445,9 @@ enum {
         CAPA_OPC_OSS_WRITE    = 1<<5,  /**< write oss object data */
         CAPA_OPC_OSS_READ     = 1<<6,  /**< read oss object data */
         CAPA_OPC_OSS_TRUNC    = 1<<7,  /**< truncate oss object */
-        CAPA_OPC_META_WRITE   = 1<<8,  /**< write object meta data */
-        CAPA_OPC_META_READ    = 1<<9,  /**< read object meta data */
-
+        CAPA_OPC_OSS_DESTROY  = 1<<8,  /**< destroy oss object */
+        CAPA_OPC_META_WRITE   = 1<<9,  /**< write object meta data */
+        CAPA_OPC_META_READ    = 1<<10, /**< read object meta data */
 };
 
 #define CAPA_OPC_OSS_RW (CAPA_OPC_OSS_READ | CAPA_OPC_OSS_WRITE)
@@ -2374,7 +2455,8 @@ enum {
         (CAPA_OPC_BODY_WRITE | CAPA_OPC_BODY_READ | CAPA_OPC_INDEX_LOOKUP | \
          CAPA_OPC_INDEX_INSERT | CAPA_OPC_INDEX_DELETE)
 #define CAPA_OPC_OSS_ONLY                                                   \
-        (CAPA_OPC_OSS_WRITE | CAPA_OPC_OSS_READ | CAPA_OPC_OSS_TRUNC)
+        (CAPA_OPC_OSS_WRITE | CAPA_OPC_OSS_READ | CAPA_OPC_OSS_TRUNC |      \
+         CAPA_OPC_OSS_DESTROY)
 #define CAPA_OPC_MDS_DEFAULT ~CAPA_OPC_OSS_ONLY
 #define CAPA_OPC_OSS_DEFAULT ~(CAPA_OPC_MDS_ONLY | CAPA_OPC_OSS_ONLY)
 
@@ -2411,11 +2493,6 @@ struct lustre_capa_key {
 
 extern void lustre_swab_lustre_capa_key(struct lustre_capa_key *k);
 
-/* quota check function */
-#define QUOTA_RET_OK           0 /**< return successfully */
-#define QUOTA_RET_NOQUOTA      1 /**< not support quota */
-#define QUOTA_RET_NOLIMIT      2 /**< quota limit isn't set */
-#define QUOTA_RET_ACQUOTA      3 /**< need to acquire extra quota */
 #endif
 
 /** @} lustreidl */
index bd76396..12a0f0e 100644 (file)
@@ -98,6 +98,8 @@ struct obd_statfs;
 #define LL_IOC_FLUSHCTX                 _IOW ('f', 166, long)
 #define LL_IOC_RMTACL                   _IOW ('f', 167, long)
 
+#define LL_IOC_GETOBDCOUNT              _IOR ('f', 168, long)
+
 #define LL_IOC_LLOOP_ATTACH             _IOWR('f', 169, long)
 #define LL_IOC_LLOOP_DETACH             _IOWR('f', 170, long)
 #define LL_IOC_LLOOP_INFO               _IOWR('f', 171, long)
@@ -228,17 +230,19 @@ static inline char *obd_uuid2str(struct obd_uuid *uuid)
         return (char *)(uuid->uuid);
 }
 
-#define LUSTRE_Q_QUOTAON  0x800002     /* turn quotas on */
-#define LUSTRE_Q_QUOTAOFF 0x800003     /* turn quotas off */
-#define LUSTRE_Q_GETINFO  0x800005     /* get information about quota files */
-#define LUSTRE_Q_SETINFO  0x800006     /* set information about quota files */
-#define LUSTRE_Q_GETQUOTA 0x800007     /* get user quota structure */
-#define LUSTRE_Q_SETQUOTA 0x800008     /* set user quota structure */
+/* these must be explicitly translated into linux Q_* in ll_dir_ioctl */
+#define LUSTRE_Q_QUOTAON    0x800002     /* turn quotas on */
+#define LUSTRE_Q_QUOTAOFF   0x800003     /* turn quotas off */
+#define LUSTRE_Q_GETINFO    0x800005     /* get information about quota files */
+#define LUSTRE_Q_SETINFO    0x800006     /* set information about quota files */
+#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_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;
@@ -306,6 +310,10 @@ enum {
 
 #endif /* !__KERNEL__ */
 
+typedef enum lustre_quota_version {
+        LUSTRE_QUOTA_V2 = 1
+} lustre_quota_version_t;
+
 /* XXX: same as if_dqinfo struct in kernel */
 struct obd_dqinfo {
         __u64 dqi_bgrace;
@@ -328,11 +336,20 @@ struct obd_dqblk {
         __u32 padding;
 };
 
+enum {
+        QC_GENERAL      = 0,
+        QC_MDTIDX       = 1,
+        QC_OSTIDX       = 2,
+        QC_UUID         = 3
+};
+
 struct if_quotactl {
         __u32                   qc_cmd;
         __u32                   qc_type;
         __u32                   qc_id;
         __u32                   qc_stat;
+        __u32                   qc_valid;
+        __u32                   qc_idx;
         struct obd_dqinfo       qc_dqinfo;
         struct obd_dqblk        qc_dqblk;
         char                    obd_type[16];
index 1fb6a7d..7f65a44 100644 (file)
@@ -95,29 +95,24 @@ enum {
         CAPA_SITE_MAX
 };
 
-static inline __u64 capa_opc(struct lustre_capa *capa)
-{
-        return capa->lc_opc;
-}
-
-static inline __u32 capa_uid(struct lustre_capa *capa)
+static inline struct lu_fid *capa_fid(struct lustre_capa *capa)
 {
-        return capa->lc_uid;
+        return &capa->lc_fid;
 }
 
-static inline struct lu_fid *capa_fid(struct lustre_capa *capa)
+static inline __u64 capa_opc(struct lustre_capa *capa)
 {
-        return &capa->lc_fid;
+        return capa->lc_opc;
 }
 
-static inline __u32 capa_keyid(struct lustre_capa *capa)
+static inline __u64 capa_uid(struct lustre_capa *capa)
 {
-        return capa->lc_keyid;
+        return capa->lc_uid;
 }
 
-static inline __u64 capa_expiry(struct lustre_capa *capa)
+static inline __u64 capa_gid(struct lustre_capa *capa)
 {
-        return capa->lc_expiry;
+        return capa->lc_gid;
 }
 
 static inline __u32 capa_flags(struct lustre_capa *capa)
@@ -127,9 +122,12 @@ static inline __u32 capa_flags(struct lustre_capa *capa)
 
 static inline __u32 capa_alg(struct lustre_capa *capa)
 {
-        __u32 alg = capa->lc_flags;
+        return (capa->lc_flags >> 24);
+}
 
-        return alg >> 24;
+static inline __u32 capa_keyid(struct lustre_capa *capa)
+{
+        return capa->lc_keyid;
 }
 
 static inline __u64 capa_key_mdsid(struct lustre_capa_key *key)
@@ -142,12 +140,23 @@ static inline __u32 capa_key_keyid(struct lustre_capa_key *key)
         return key->lk_keyid;
 }
 
+static inline __u32 capa_timeout(struct lustre_capa *capa)
+{
+        return capa->lc_timeout;
+}
+
+static inline __u32 capa_expiry(struct lustre_capa *capa)
+{
+        return capa->lc_expiry;
+}
+
 #define DEBUG_CAPA(level, c, fmt, args...)                                     \
 do {                                                                           \
-CDEBUG(level, fmt " capability@%p uid %u opc "LPX64" fid "DFID" keyid %u "     \
-       "expiry "LPU64" flags %u alg %d\n",                                     \
-       ##args, c, capa_uid(c), capa_opc(c), PFID(capa_fid(c)), capa_keyid(c),  \
-       capa_expiry(c), capa_flags(c), capa_alg(c));                            \
+CDEBUG(level, fmt " capability@%p fid "DFID" opc "LPX64" uid "LPU64" gid "     \
+       LPU64" flags %u alg %d keyid %u timeout %u expiry %u\n",                \
+       ##args, c, PFID(capa_fid(c)), capa_opc(c), capa_uid(c), capa_gid(c),    \
+       capa_flags(c), capa_alg(c), capa_keyid(c), capa_timeout(c),             \
+       capa_expiry(c));                                                        \
 } while (0)
 
 #define DEBUG_CAPA_KEY(level, k, fmt, args...)                                 \
@@ -172,38 +181,33 @@ struct obd_capa *capa_lookup(struct hlist_head *hash, struct lustre_capa *capa,
                              int alive);
 
 int capa_hmac(__u8 *hmac, struct lustre_capa *capa, __u8 *key);
+int capa_encrypt_id(__u32 *d, __u32 *s, __u8 *key, int keylen);
+int capa_decrypt_id(__u32 *d, __u32 *s, __u8 *key, int keylen);
 void capa_cpy(void *dst, struct obd_capa *ocapa);
-
-char *dump_capa_content(char *buf, char *key, int len);
-
 static inline struct obd_capa *alloc_capa(int site)
 {
 #ifdef __KERNEL__
         struct obd_capa *ocapa;
 
+        if (unlikely(site != CAPA_SITE_CLIENT && site != CAPA_SITE_SERVER))
+                return ERR_PTR(-EINVAL);
+
         OBD_SLAB_ALLOC(ocapa, capa_cachep, GFP_KERNEL, sizeof(*ocapa));
-        if (ocapa) {
-                atomic_set(&ocapa->c_refc, 0);
-                spin_lock_init(&ocapa->c_lock);
-                CFS_INIT_LIST_HEAD(&ocapa->c_list);
-                ocapa->c_site = site;
-        }
-        return ocapa;
-#else
-        return NULL;
-#endif
-}
+        if (unlikely(!ocapa))
+                return ERR_PTR(-ENOMEM);
+
+        CFS_INIT_LIST_HEAD(&ocapa->c_list);
+        atomic_set(&ocapa->c_refc, 1);
+        spin_lock_init(&ocapa->c_lock);
+        ocapa->c_site = site;
+        if (ocapa->c_site == CAPA_SITE_CLIENT)
+                CFS_INIT_LIST_HEAD(&ocapa->u.cli.lli_list);
+        else
+                CFS_INIT_HLIST_NODE(&ocapa->u.tgt.c_hash);
 
-static inline void free_capa(struct obd_capa *ocapa)
-{
-#ifdef __KERNEL__
-        if (atomic_read(&ocapa->c_refc)) {
-                DEBUG_CAPA(D_ERROR, &ocapa->c_capa, "refc %d for",
-                           atomic_read(&ocapa->c_refc));
-                LBUG();
-        }
-        OBD_SLAB_FREE(ocapa, capa_cachep, sizeof(*ocapa));
+        return ocapa;
 #else
+        return ERR_PTR(-EOPNOTSUPP);
 #endif
 }
 
@@ -225,7 +229,19 @@ static inline void capa_put(struct obd_capa *ocapa)
                 DEBUG_CAPA(D_ERROR, &ocapa->c_capa, "refc is 0 for");
                 LBUG();
         }
-        atomic_dec(&ocapa->c_refc);
+
+        if (atomic_dec_and_test(&ocapa->c_refc)) {
+                LASSERT(list_empty(&ocapa->c_list));
+                if (ocapa->c_site == CAPA_SITE_CLIENT) {
+                        LASSERT(list_empty(&ocapa->u.cli.lli_list));
+                } else {
+                        struct hlist_node *hnode;
+
+                        hnode = &ocapa->u.tgt.c_hash;
+                        LASSERT(!hnode->next && !hnode->pprev);
+                }
+                OBD_SLAB_FREE(ocapa, capa_cachep, sizeof(*ocapa));
+        }
 }
 
 static inline int open_flags_to_accmode(int flags)
@@ -253,6 +269,11 @@ static inline void set_capa_expiry(struct obd_capa *ocapa)
                                        cfs_time_seconds(expiry));
 }
 
+static inline int capa_is_expired_sec(struct lustre_capa *capa)
+{
+        return (capa->lc_expiry - cfs_time_current_sec() <= 0);
+}
+
 static inline int capa_is_expired(struct obd_capa *ocapa)
 {
         return cfs_time_beforeq(ocapa->c_expiry, cfs_time_current());
@@ -284,5 +305,11 @@ struct filter_capa_key {
         struct lustre_capa_key  k_key;
 };
 
+enum {
+        LC_ID_NONE      = 0,
+        LC_ID_PLAIN     = 1,
+        LC_ID_CONVERT   = 2
+};
+
 #define BYPASS_CAPA (struct lustre_capa *)ERR_PTR(-ENOENT)
 #endif /* __LINUX_CAPA_H_ */
index 4851fbc..b2a5c86 100644 (file)
@@ -56,7 +56,6 @@ struct mdt_export_data {
         __u64                   med_ibits_known;
         loff_t                  med_lr_off;
         int                     med_lr_idx;
-        unsigned int            med_rmtclient:1; /* remote client? */
         struct semaphore           med_idmap_sem;
         struct lustre_idmap_table *med_idmap;
 };
@@ -178,6 +177,20 @@ static inline int exp_connect_lru_resize(struct obd_export *exp)
         return !!(exp->exp_connect_flags & OBD_CONNECT_LRU_RESIZE);
 }
 
+static inline int exp_connect_rmtclient(struct obd_export *exp)
+{
+        LASSERT(exp != NULL);
+        return !!(exp->exp_connect_flags & OBD_CONNECT_RMT_CLIENT);
+}
+
+static inline int client_is_remote(struct obd_export *exp)
+{
+        struct obd_import *imp = class_exp2cliimp(exp);
+
+        return !!(imp->imp_connect_data.ocd_connect_flags &
+                  OBD_CONNECT_RMT_CLIENT);
+}
+
 static inline int imp_connect_lru_resize(struct obd_import *imp)
 {
         struct obd_connect_data *ocd;
index 83697fe..ba36693 100644 (file)
@@ -80,13 +80,12 @@ int target_pack_pool_reply(struct ptlrpc_request *req);
 int target_handle_ping(struct ptlrpc_request *req);
 void target_committed_to_req(struct ptlrpc_request *req);
 
-#ifdef HAVE_QUOTA_SUPPORT
 /* quotacheck callback, dqacq/dqrel callback handler */
 int target_handle_qc_callback(struct ptlrpc_request *req);
+#ifdef HAVE_QUOTA_SUPPORT
 int target_handle_dqacq_callback(struct ptlrpc_request *req);
 #else
 #define target_handle_dqacq_callback(req) ldlm_callback_reply(req, -ENOTSUPP)
-#define target_handle_qc_callback(req) (0)
 #endif
 
 #define OBD_RECOVERY_MAX_TIME (obd_timeout * 18) /* b13079 */
index 558930d..1bb9ac2 100644 (file)
@@ -212,8 +212,8 @@ union ptlrpc_async_args {
          * big enough.  For _tons_ of context, OBD_ALLOC a struct and store
          * a pointer to it here.  The pointer_arg ensures this struct is at
          * least big enough for that. */
-        void      *pointer_arg[9];
-        __u64      space[5];
+        void      *pointer_arg[11];
+        __u64      space[6];
 };
 
 struct ptlrpc_request_set;
@@ -625,13 +625,23 @@ struct ptlrpc_bulk_desc {
 };
 
 struct ptlrpc_thread {
-
-        struct list_head t_link; /* active threads in svc->srv_threads */
-
-        void *t_data;            /* thread-private data (preallocated memory) */
+        /**
+         * active threads in svc->srv_threads
+         */
+        struct list_head t_link;
+        /**
+         * thread-private data (preallocated memory)
+         */
+        void *t_data;
         __u32 t_flags;
-
-        unsigned int t_id; /* service thread index, from ptlrpc_start_threads */
+        /**
+         * service thread index, from ptlrpc_start_threads
+         */
+        unsigned int t_id;
+        /**
+         * put watchdog in the structure per thread b=14840
+         */
+        struct lc_watchdog *t_watchdog;
         cfs_waitq_t t_ctl_waitq;
         struct lu_env *t_env;
 };
index 2b26e24..b0dc442 100644 (file)
@@ -50,6 +50,8 @@
 #include <lustre/lustre_idl.h>
 #include <lustre_net.h>
 #include <lvfs.h>
+#include <obd_support.h>
+#include <class_hash.h>
 
 struct obd_device;
 struct client_obd;
@@ -62,6 +64,64 @@ struct client_obd;
 
 #ifdef __KERNEL__
 
+#ifdef LPROCFS
+enum {
+        LQUOTA_FIRST_STAT = 0,
+        /** @{ */
+        /**
+         * these four are for measuring quota requests, for both of
+         * quota master and quota slaves
+         */
+        LQUOTA_SYNC_ACQ = LQUOTA_FIRST_STAT,
+        LQUOTA_SYNC_REL,
+        LQUOTA_ASYNC_ACQ,
+        LQUOTA_ASYNC_REL,
+        /** }@ */
+        /** @{ */
+        /**
+         * these four measure how much time I/O threads spend on dealing
+         * with quota before and after writing data or creating files,
+         * only for quota slaves(lquota_chkquota and lquota_pending_commit)
+         */
+        LQUOTA_WAIT_FOR_CHK_BLK,
+        LQUOTA_WAIT_FOR_CHK_INO,
+        LQUOTA_WAIT_FOR_COMMIT_BLK,
+        LQUOTA_WAIT_FOR_COMMIT_INO,
+        /** }@ */
+        /** @{ */
+        /**
+         * these two are for measuring time waiting return of quota reqs
+         * (qctxt_wait_pending_dqacq), only for quota salves
+         */
+        LQUOTA_WAIT_PENDING_BLK_QUOTA,
+        LQUOTA_WAIT_PENDING_INO_QUOTA,
+        /** }@ */
+        /** @{ */
+        /**
+         * these two are for those when they are calling
+         * qctxt_wait_pending_dqacq, the quota req has returned already,
+         * only for quota salves
+         */
+        LQUOTA_NOWAIT_PENDING_BLK_QUOTA,
+        LQUOTA_NOWAIT_PENDING_INO_QUOTA,
+        /** }@ */
+        /** @{ */
+        /**
+         * these are for quota ctl
+         */
+        LQUOTA_QUOTA_CTL,
+        /** }@ */
+        /** @{ */
+        /**
+         * these are for adjust quota qunit, for both of
+         * quota master and quota slaves
+         */
+        LQUOTA_ADJUST_QUNIT,
+        LQUOTA_LAST_STAT
+        /** }@ */
+};
+#endif  /* LPROCFS */
+
 /* structures to access admin quotafile */
 struct lustre_mem_dqinfo {
         unsigned int dqi_bgrace;
@@ -75,28 +135,45 @@ struct lustre_mem_dqinfo {
 struct lustre_quota_info {
         struct file *qi_files[MAXQUOTAS];
         struct lustre_mem_dqinfo qi_info[MAXQUOTAS];
+        lustre_quota_version_t qi_version;
 };
 
 #define DQ_STATUS_AVAIL         0x0     /* Available dquot */
 #define DQ_STATUS_SET           0x01    /* Sombody is setting dquot */
 #define DQ_STATUS_RECOVERY      0x02    /* dquot is in recovery */
 
+struct lustre_mem_dqblk {
+        __u64 dqb_bhardlimit;  /**< absolute limit on disk blks alloc */
+        __u64 dqb_bsoftlimit;  /**< preferred limit on disk blks */
+        __u64 dqb_curspace;    /**< current used space */
+        __u64 dqb_ihardlimit;  /**< absolute limit on allocated inodes */
+        __u64 dqb_isoftlimit;  /**< preferred inode limit */
+        __u64 dqb_curinodes;   /**< current # allocated inodes */
+        time_t dqb_btime;      /**< time limit for excessive disk use */
+        time_t dqb_itime;      /**< time limit for excessive inode use */
+};
+
 struct lustre_dquot {
-        /* Hash list in memory, protect by dquot_hash_lock */
+        /** Hash list in memory, protect by dquot_hash_lock */
         struct list_head dq_hash;
-        /* Protect the data in lustre_dquot */
+        /** Protect the data in lustre_dquot */
         struct semaphore dq_sem;
-        /* Use count */
+        /** Use count */
         int dq_refcnt;
-        /* Pointer of quota info it belongs to */
+        /** Pointer of quota info it belongs to */
         struct lustre_quota_info *dq_info;
-        
-        loff_t dq_off;                  /* Offset of dquot on disk */
-        unsigned int dq_id;             /* ID this applies to (uid, gid) */
-        int dq_type;                    /* Type fo quota (USRQUOTA, GRPQUOUTA) */
-        unsigned short dq_status;       /* See DQ_STATUS_ */
-        unsigned long dq_flags;         /* See DQ_ in quota.h */
-        struct mem_dqblk dq_dqb;        /* Diskquota usage */
+        /** Offset of dquot on disk */
+        loff_t dq_off;
+        /** ID this applies to (uid, gid) */
+        unsigned int dq_id;
+        /** Type fo quota (USRQUOTA, GRPQUOUTA) */
+        int dq_type;
+        /** See DQ_STATUS_ */
+        unsigned short dq_status;
+        /** See DQ_ in quota.h */
+        unsigned long dq_flags;
+        /** Diskquota usage */
+        struct lustre_mem_dqblk dq_dqb;
 };
 
 struct dquot_id {
@@ -110,37 +187,234 @@ struct dquot_id {
 #define QFILE_INIT_INFO         4
 #define QFILE_RD_DQUOT          5
 #define QFILE_WR_DQUOT          6
+#define QFILE_CONVERT           7
 
 /* admin quotafile operations */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 int lustre_check_quota_file(struct lustre_quota_info *lqi, int type);
 int lustre_read_quota_info(struct lustre_quota_info *lqi, int type);
 int lustre_write_quota_info(struct lustre_quota_info *lqi, int type);
 int lustre_read_dquot(struct lustre_dquot *dquot);
 int lustre_commit_dquot(struct lustre_dquot *dquot);
 int lustre_init_quota_info(struct lustre_quota_info *lqi, int type);
-int lustre_get_qids(struct file *file, struct inode *inode, int type, 
+int lustre_get_qids(struct file *file, struct inode *inode, int type,
                     struct list_head *list);
+int lustre_quota_convert(struct lustre_quota_info *lqi, int type);
+#else
+
+#ifndef DQ_FAKE_B
+#define DQ_FAKE_B       6
+#endif
+
+static inline int lustre_check_quota_file(struct lustre_quota_info *lqi,
+                                          int type)
+{
+        return 0;
+}
+static inline int lustre_read_quota_info(struct lustre_quota_info *lqi,
+                                         int type)
+{
+        return 0;
+}
+static inline int lustre_write_quota_info(struct lustre_quota_info *lqi,
+                                          int type)
+{
+        return 0;
+}
+static inline int lustre_read_dquot(struct lustre_dquot *dquot)
+{
+        return 0;
+}
+static inline int lustre_commit_dquot(struct lustre_dquot *dquot)
+{
+        return 0;
+}
+static inline int lustre_init_quota_info(struct lustre_quota_info *lqi,
+                                         int type)
+{
+        return 0;
+}
+static inline int lustre_quota_convert(struct lustre_quota_info *lqi,
+                                       int type)
+{
+        return 0;
+}
+#endif  /* KERNEL_VERSION(2,5,0) */
 
 #define LL_DQUOT_OFF(sb)    DQUOT_OFF(sb)
 
 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_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 */
-        unsigned long lqc_iunit_sz;     /* Unit size of file quota */
-        unsigned long lqc_itune_sz;     /* Trigger dqacq when available file quota less than
-                                         * this value, trigger dqrel when available file quota
-                                         * more than this value + 1 iunit */
-        unsigned long lqc_bunit_sz;     /* Unit size of block quota */
-        unsigned long lqc_btune_sz;     /* See comment of lqc_itune_sz */
+        /** superblock this applies to */
+        struct super_block *lqc_sb;
+        /** obd_device_target for obt_rwsem */
+        struct obd_device_target *lqc_obt;
+        /** import used to send dqacq/dqrel RPC */
+        struct obd_import *lqc_import;
+        /** dqacq/dqrel RPC handler, only for quota master */
+        dqacq_handler_t lqc_handler;
+        /** quota flags */
+        unsigned long lqc_flags;
+        /** @{ */
+        unsigned long lqc_recovery:1,   /** Doing recovery */
+                      lqc_switch_qs:1,  /**
+                                         * the function of change qunit size
+                                         * 0:Off, 1:On
+                                         */
+                      lqc_valid:1,      /** this qctxt is valid or not */
+                      lqc_setup:1;      /**
+                                         * tell whether of not quota_type has
+                                         * been processed, so that the master
+                                         * knows when it can start processing
+                                         * incoming acq/rel quota requests
+                                         */
+        /** }@ */
+        /**
+         * original unit size of file quota and
+         * upper limitation for adjust file qunit
+         */
+        unsigned long lqc_iunit_sz;
+        /**
+         * Trigger dqacq when available file
+         * quota less than this value, trigger
+         * dqrel when available file quota
+         * more than this value + 1 iunit
+         */
+        unsigned long lqc_itune_sz;
+        /**
+         * original unit size of block quota and
+         * upper limitation for adjust block qunit
+         */
+        unsigned long lqc_bunit_sz;
+        /** See comment of lqc_itune_sz */
+        unsigned long lqc_btune_sz;
+        /** all lustre_qunit_size structures */
+        struct lustre_hash *lqc_lqs_hash;
+
+        /** @{ */
+        /**
+         * the values below are relative to how master change its qunit sizes
+         */
+        /**
+         * this affects the boundary of
+         * shrinking and enlarging qunit size. default=4
+         */
+        unsigned long lqc_cqs_boundary_factor;
+        /** the least value of block qunit */
+        unsigned long lqc_cqs_least_bunit;
+        /** the least value of inode qunit */
+        unsigned long lqc_cqs_least_iunit;
+        /**
+         * when enlarging, qunit size will
+         * mutilple it; when shrinking,
+         * qunit size will divide it
+         */
+        unsigned long lqc_cqs_qs_factor;
+        /**
+         * avoid ping-pong effect of
+         * adjusting qunit size. How many
+         * seconds must be waited between
+         * enlarging and shinking qunit
+         */
+        /** }@ */
+        int           lqc_switch_seconds;
+        /**
+         * when blk qunit reaches this value,
+         * later write reqs from client should be sync b=16642
+         */
+        int           lqc_sync_blk;
+        /** guard lqc_imp_valid now */
+        spinlock_t    lqc_lock;
+        /**
+         * when mds isn't connected, threads
+         * on osts who send the quota reqs
+         * with wait==1 will be put here b=14840
+         */
+        cfs_waitq_t   lqc_wait_for_qmaster;
+        struct proc_dir_entry *lqc_proc_dir;
+        /** lquota statistics */
+        struct lprocfs_stats  *lqc_stats;
 };
 
+#define QUOTA_MASTER_READY(qctxt)   (qctxt)->lqc_setup = 1
+#define QUOTA_MASTER_UNREADY(qctxt) (qctxt)->lqc_setup = 0
+
+struct lustre_qunit_size {
+        struct hlist_node lqs_hash; /** the hash entry */
+        unsigned int lqs_id;        /** id of user/group */
+        unsigned long lqs_flags;    /** is user/group; FULLBUF or LESSBUF */
+        unsigned long lqs_iunit_sz; /** Unit size of file quota currently */
+        /**
+         * Trigger dqacq when available file quota
+         * less than this value, trigger dqrel
+         * when more than this value + 1 iunit
+         */
+        unsigned long lqs_itune_sz;
+        unsigned long lqs_bunit_sz; /** Unit size of block quota currently */
+        unsigned long lqs_btune_sz; /** See comment of lqs itune sz */
+        /** the blocks reached ost and don't finish */
+        unsigned long lqs_bwrite_pending;
+        /** the inodes reached mds and don't finish */
+        unsigned long lqs_iwrite_pending;
+        /** when inodes are allocated/released, this value will record it */
+        long long lqs_ino_rec;
+        /** when blocks are allocated/released, this value will record it */
+        long long lqs_blk_rec;
+        atomic_t lqs_refcount;
+        cfs_time_t lqs_last_bshrink;   /** time of last block shrink */
+        cfs_time_t lqs_last_ishrink;   /** time of last inode shrink */
+        spinlock_t lqs_lock;
+        struct quota_adjust_qunit lqs_key; /** hash key */
+        struct lustre_quota_ctxt *lqs_ctxt; /** quota ctxt */
+};
+
+#define LQS_IS_GRP(lqs)    ((lqs)->lqs_flags & LQUOTA_FLAGS_GRP)
+#define LQS_IS_ADJBLK(lqs) ((lqs)->lqs_flags & LQUOTA_FLAGS_ADJBLK)
+#define LQS_IS_ADJINO(lqs) ((lqs)->lqs_flags & LQUOTA_FLAGS_ADJINO)
+
+#define LQS_SET_GRP(lqs)    ((lqs)->lqs_flags |= LQUOTA_FLAGS_GRP)
+#define LQS_SET_ADJBLK(lqs) ((lqs)->lqs_flags |= LQUOTA_FLAGS_ADJBLK)
+#define LQS_SET_ADJINO(lqs) ((lqs)->lqs_flags |= LQUOTA_FLAGS_ADJINO)
+
+static inline void lqs_getref(struct lustre_qunit_size *lqs)
+{
+        atomic_inc(&lqs->lqs_refcount);
+        CDEBUG(D_QUOTA, "lqs=%p refcount %d\n",
+               lqs, atomic_read(&lqs->lqs_refcount));
+}
+
+static inline void lqs_putref(struct lustre_qunit_size *lqs)
+{
+        LASSERT(atomic_read(&lqs->lqs_refcount) > 0);
+
+        /* killing last ref, let's let hash table kill it */
+        if (atomic_read(&lqs->lqs_refcount) == 1) {
+                lustre_hash_del(lqs->lqs_ctxt->lqc_lqs_hash,
+                                &lqs->lqs_key, &lqs->lqs_hash);
+                OBD_FREE_PTR(lqs);
+        } else {
+                atomic_dec(&lqs->lqs_refcount);
+                CDEBUG(D_QUOTA, "lqs=%p refcount %d\n",
+                       lqs, atomic_read(&lqs->lqs_refcount));
+
+        }
+}
+
+static inline void lqs_initref(struct lustre_qunit_size *lqs)
+{
+        atomic_set(&lqs->lqs_refcount, 0);
+}
+
 #else
 
 struct lustre_quota_info {
@@ -149,6 +423,9 @@ struct lustre_quota_info {
 struct lustre_quota_ctxt {
 };
 
+#define QUOTA_MASTER_READY(qctxt)
+#define QUOTA_MASTER_UNREADY(qctxt)
+
 #endif  /* !__KERNEL__ */
 
 #else
@@ -168,58 +445,109 @@ struct lustre_quota_ctxt {
 #define MIN_QLIMIT      1
 
 struct quotacheck_thread_args {
-        struct obd_export   *qta_exp;   /* obd export */
-        struct obd_quotactl  qta_oqctl; /* obd_quotactl args */
-        struct super_block  *qta_sb;    /* obd super block */
-        atomic_t            *qta_sem;   /* obt_quotachecking */
+        struct obd_export   *qta_exp;   /** obd export */
+        struct obd_device   *qta_obd;   /** obd device */
+        struct obd_quotactl  qta_oqctl; /** obd_quotactl args */
+        struct super_block  *qta_sb;    /** obd super block */
+        atomic_t            *qta_sem;   /** obt_quotachecking */
 };
 
+struct obd_trans_info;
+typedef int (*quota_acquire)(struct obd_device *obd, unsigned int uid,
+                             unsigned int gid, struct obd_trans_info *oti,
+                             int isblk);
+
 typedef struct {
         int (*quota_init) (void);
         int (*quota_exit) (void);
         int (*quota_setup) (struct obd_device *);
         int (*quota_cleanup) (struct obd_device *);
-        /* For quota master, close admin quota files */
+        /**
+         * For quota master, close admin quota files
+         */
         int (*quota_fs_cleanup) (struct obd_device *);
-        int (*quota_ctl) (struct obd_export *, struct obd_quotactl *);
-        int (*quota_check) (struct obd_export *, struct obd_quotactl *);
+        int (*quota_ctl) (struct obd_device *, struct obd_export *,
+                          struct obd_quotactl *);
+        int (*quota_check) (struct obd_device *, struct obd_export *,
+                            struct obd_quotactl *);
         int (*quota_recovery) (struct obd_device *);
-        
-        /* For quota master/slave, adjust quota limit after fs operation */
-        int (*quota_adjust) (struct obd_device *, unsigned int[], 
-                             unsigned int[], int, int); 
-        
-        /* For quota slave, set import, trigger quota recovery */
-        int (*quota_setinfo) (struct obd_export *, struct obd_device *);
-        
-        /* For quota slave, set proper thread resoure capability */
+
+        /**
+         * For quota master/slave, adjust quota limit after fs operation
+         */
+        int (*quota_adjust) (struct obd_device *, unsigned int[],
+                             unsigned int[], int, int);
+
+        /**
+         * For quota slave, set import, trigger quota recovery,
+         * For quota master, set lqc_setup
+         */
+        int (*quota_setinfo) (struct obd_device *, void *);
+
+        /**
+         * For quota slave, clear import when relative import is invalid
+         */
+        int (*quota_clearinfo) (struct obd_export *, struct obd_device *);
+
+        /**
+         * For quota slave, set proper thread resoure capability
+         */
         int (*quota_enforce) (struct obd_device *, unsigned int);
-        
-        /* For quota slave, check whether specified uid/gid is over quota */
+
+        /**
+         * For quota slave, check whether specified uid/gid is over quota
+         */
         int (*quota_getflag) (struct obd_device *, struct obdo *);
-        
-        /* For quota slave, acquire/release quota from master if needed */
-        int (*quota_acquire) (struct obd_device *, unsigned int, unsigned int);
-        
-        /* For quota slave, check whether specified uid/gid's remaining quota
-         * can finish a write rpc */
+
+        /**
+         * For quota slave, acquire/release quota from master if needed
+         */
+        int (*quota_acquire) (struct obd_device *, unsigned int, unsigned int,
+                              struct obd_trans_info *, int);
+
+        /**
+         * For quota slave, check whether specified uid/gid's remaining quota
+         * can finish a block_write or inode_create rpc. It updates the pending
+         * record of block and inode, acquires quota if necessary
+         */
         int (*quota_chkquota) (struct obd_device *, unsigned int, unsigned int,
-                               int);
+                               int, int *, quota_acquire,
+                               struct obd_trans_info *, int);
 
-        /* For quota client, poll if the quota check done */
+        /**
+         * For quota client, poll if the quota check done
+         */
         int (*quota_poll_check) (struct obd_export *, struct if_quotacheck *);
-        
-        /* For quota client, check whether specified uid/gid is over quota */
+
+        /**
+         * For quota client, check whether specified uid/gid is over quota
+         */
         int (*quota_chkdq) (struct client_obd *, unsigned int, unsigned int);
-        
-        /* For quota client, set over quota flag for specifed uid/gid */
+
+        /**
+         * For quota client, the actions after the pending write is committed
+         */
+        int (*quota_pending_commit) (struct obd_device *, unsigned int,
+                                     unsigned int, int, int);
+
+        /**
+         * For quota client, set over quota flag for specifed uid/gid
+         */
         int (*quota_setdq) (struct client_obd *, unsigned int, unsigned int,
                             obd_flag, obd_flag);
+
+        /**
+         * For adjusting qunit size b=10600
+         */
+        int (*quota_adjust_qunit) (struct obd_export *exp,
+                                   struct quota_adjust_qunit *oqaq,
+                                   struct lustre_quota_ctxt *qctxt);
+
 } quota_interface_t;
 
 #define Q_COPY(out, in, member) (out)->member = (in)->member
 
-#define QUOTA_OP(interface, op) interface->quota_ ## op         
+#define QUOTA_OP(interface, op) interface->quota_ ## op
 
 #define QUOTA_CHECK_OP(interface, op)                           \
 do {                                                            \
@@ -235,39 +563,39 @@ static inline int lquota_init(quota_interface_t *interface)
 {
         int rc;
         ENTRY;
-        
+
         QUOTA_CHECK_OP(interface, init);
         rc = QUOTA_OP(interface, init)();
         RETURN(rc);
 }
 
-static inline int lquota_exit(quota_interface_t *interface) 
+static inline int lquota_exit(quota_interface_t *interface)
 {
         int rc;
         ENTRY;
-        
+
         QUOTA_CHECK_OP(interface, exit);
         rc = QUOTA_OP(interface, exit)();
         RETURN(rc);
 }
 
 static inline int lquota_setup(quota_interface_t *interface,
-                               struct obd_device *obd) 
+                               struct obd_device *obd)
 {
         int rc;
         ENTRY;
-        
+
         QUOTA_CHECK_OP(interface, setup);
         rc = QUOTA_OP(interface, setup)(obd);
         RETURN(rc);
 }
 
 static inline int lquota_cleanup(quota_interface_t *interface,
-                                 struct obd_device *obd) 
+                                 struct obd_device *obd)
 {
         int rc;
         ENTRY;
-        
+
         QUOTA_CHECK_OP(interface, cleanup);
         rc = QUOTA_OP(interface, cleanup)(obd);
         RETURN(rc);
@@ -278,32 +606,57 @@ static inline int lquota_fs_cleanup(quota_interface_t *interface,
 {
         int rc;
         ENTRY;
-        
+
         QUOTA_CHECK_OP(interface, fs_cleanup);
         rc = QUOTA_OP(interface, fs_cleanup)(obd);
         RETURN(rc);
 }
 
 static inline int lquota_recovery(quota_interface_t *interface,
-                                  struct obd_device *obd) 
-{        
+                                  struct obd_device *obd)
+{
         int rc;
         ENTRY;
-        
+
         QUOTA_CHECK_OP(interface, recovery);
         rc = QUOTA_OP(interface, recovery)(obd);
         RETURN(rc);
 }
 
+static inline int lquota_check(quota_interface_t *interface,
+                               struct obd_device *obd,
+                               struct obd_export *exp,
+                               struct obd_quotactl *oqctl)
+{
+        int rc;
+        ENTRY;
+
+        QUOTA_CHECK_OP(interface, check);
+        rc = QUOTA_OP(interface, check)(obd, exp, oqctl);
+        RETURN(rc);
+}
+
+static inline int lquota_ctl(quota_interface_t *interface,
+                             struct obd_device *obd,
+                             struct obd_quotactl *oqctl)
+{
+        int rc;
+        ENTRY;
+
+        QUOTA_CHECK_OP(interface, ctl);
+        rc = QUOTA_OP(interface, ctl)(obd, NULL, oqctl);
+        RETURN(rc);
+}
+
 static inline int lquota_adjust(quota_interface_t *interface,
-                                struct obd_device *obd, 
-                                unsigned int qcids[], 
-                                unsigned int qpids[], 
-                                int rc, int opc) 
+                                struct obd_device *obd,
+                                unsigned int qcids[],
+                                unsigned int qpids[],
+                                int rc, int opc)
 {
         int ret;
         ENTRY;
-        
+
         QUOTA_CHECK_OP(interface, adjust);
         ret = QUOTA_OP(interface, adjust)(obd, qcids, qpids, rc, opc);
         RETURN(ret);
@@ -315,7 +668,7 @@ static inline int lquota_chkdq(quota_interface_t *interface,
 {
         int rc;
         ENTRY;
-        
+
         QUOTA_CHECK_OP(interface, chkdq);
         rc = QUOTA_OP(interface, chkdq)(cli, uid, gid);
         RETURN(rc);
@@ -328,7 +681,7 @@ static inline int lquota_setdq(quota_interface_t *interface,
 {
         int rc;
         ENTRY;
-        
+
         QUOTA_CHECK_OP(interface, setdq);
         rc = QUOTA_OP(interface, setdq)(cli, uid, gid, valid, flags);
         RETURN(rc);
@@ -340,26 +693,37 @@ static inline int lquota_poll_check(quota_interface_t *interface,
 {
         int rc;
         ENTRY;
-        
+
         QUOTA_CHECK_OP(interface, poll_check);
         rc = QUOTA_OP(interface, poll_check)(exp, qchk);
         RETURN(rc);
 }
 
-       
 static inline int lquota_setinfo(quota_interface_t *interface,
-                                 struct obd_export *exp, 
-                                 struct obd_device *obd) 
+                                 struct obd_device *obd,
+                                 void *data)
 {
         int rc;
         ENTRY;
 
         QUOTA_CHECK_OP(interface, setinfo);
-        rc = QUOTA_OP(interface, setinfo)(exp, obd);
+        rc = QUOTA_OP(interface, setinfo)(obd, data);
+        RETURN(rc);
+}
+
+static inline int lquota_clearinfo(quota_interface_t *interface,
+                                   struct obd_export *exp,
+                                   struct obd_device *obd)
+{
+        int rc;
+        ENTRY;
+
+        QUOTA_CHECK_OP(interface, clearinfo);
+        rc = QUOTA_OP(interface, clearinfo)(exp, obd);
         RETURN(rc);
 }
 
-static inline int lquota_enforce(quota_interface_t *interface, 
+static inline int lquota_enforce(quota_interface_t *interface,
                                  struct obd_device *obd,
                                  unsigned int ignore)
 {
@@ -381,57 +745,60 @@ static inline int lquota_getflag(quota_interface_t *interface,
         rc = QUOTA_OP(interface, getflag)(obd, oa);
         RETURN(rc);
 }
-        
-static inline int lquota_acquire(quota_interface_t *interface,
-                                 struct obd_device *obd, 
-                                 unsigned int uid, unsigned int gid)
+
+static inline int lquota_chkquota(quota_interface_t *interface,
+                                  struct obd_device *obd,
+                                  unsigned int uid, unsigned int gid, int count,
+                                  int *flag, struct obd_trans_info *oti,
+                                  int isblk)
 {
         int rc;
         ENTRY;
 
+        QUOTA_CHECK_OP(interface, chkquota);
         QUOTA_CHECK_OP(interface, acquire);
-        rc = QUOTA_OP(interface, acquire)(obd, uid, gid);
+        rc = QUOTA_OP(interface, chkquota)(obd, uid, gid, count, flag,
+                                           QUOTA_OP(interface, acquire), oti,
+                                           isblk);
         RETURN(rc);
 }
 
-static inline int lquota_chkquota(quota_interface_t *interface,
-                                  struct obd_device *obd,
-                                  unsigned int uid, unsigned int gid,
-                                  int npage)
+static inline int lquota_pending_commit(quota_interface_t *interface,
+                                        struct obd_device *obd,
+                                        unsigned int uid, unsigned int gid,
+                                        int npage, int isblk)
 {
         int rc;
         ENTRY;
-        
-        QUOTA_CHECK_OP(interface, chkquota);
-        rc = QUOTA_OP(interface, chkquota)(obd, uid, gid, npage);
+
+        QUOTA_CHECK_OP(interface, pending_commit);
+        rc = QUOTA_OP(interface, pending_commit)(obd, uid, gid, npage, isblk);
         RETURN(rc);
 }
 
-int lprocfs_rd_bunit(char *page, char **start, off_t off, int count, 
-                     int *eof, void *data);
-int lprocfs_rd_iunit(char *page, char **start, off_t off, int count, 
-                     int *eof, void *data);
-int lprocfs_wr_bunit(struct file *file, const char *buffer,
-                     unsigned long count, void *data);
-int lprocfs_wr_iunit(struct file *file, const char *buffer,
-                     unsigned long count, void *data);
-int lprocfs_rd_btune(char *page, char **start, off_t off, int count, 
-                     int *eof, void *data);
-int lprocfs_rd_itune(char *page, char **start, off_t off, int count, 
-                     int *eof, void *data);
-int lprocfs_wr_btune(struct file *file, const char *buffer,
-                     unsigned long count, void *data);
-int lprocfs_wr_itune(struct file *file, const char *buffer,
-                     unsigned long count, void *data);
-int lprocfs_rd_type(char *page, char **start, off_t off, int count, 
-                    int *eof, void *data);
-int lprocfs_wr_type(struct file *file, const char *buffer,
-                    unsigned long count, void *data);
-
 #ifndef __KERNEL__
 extern quota_interface_t osc_quota_interface;
-extern quota_interface_t mdc_quota_interface;
 extern quota_interface_t lov_quota_interface;
+extern quota_interface_t mdc_quota_interface;
+extern quota_interface_t lmv_quota_interface;
+
+#ifndef MAXQUOTAS
+#define MAXQUOTAS 2
+#endif
+
+#ifndef USRQUOTA
+#define USRQUOTA 0
 #endif
 
+#ifndef GRPQUOTA
+#define GRPQUOTA 1
+#endif
+
+#endif
+
+#define LUSTRE_ADMIN_QUOTAFILES_V2 {\
+        "admin_quotafile_v2.usr",       /** user admin quotafile */\
+        "admin_quotafile_v2.grp"        /** group admin quotafile */\
+}
+
 #endif /* _LUSTRE_QUOTA_H */
index 1853571..4f0c777 100644 (file)
@@ -177,6 +177,7 @@ extern const struct req_format RQF_OST_CONNECT;
 extern const struct req_format RQF_OST_DISCONNECT;
 extern const struct req_format RQF_OST_QUOTACHECK;
 extern const struct req_format RQF_OST_QUOTACTL;
+extern const struct req_format RQF_OST_QUOTA_ADJUST_QUNIT;
 extern const struct req_format RQF_OST_GETATTR;
 extern const struct req_format RQF_OST_SETATTR;
 extern const struct req_format RQF_OST_CREATE;
@@ -244,6 +245,7 @@ extern const struct req_msg_field RMF_CAPA1;
 extern const struct req_msg_field RMF_CAPA2;
 extern const struct req_msg_field RMF_OBD_QUOTACHECK;
 extern const struct req_msg_field RMF_OBD_QUOTACTL;
+extern const struct req_msg_field RMF_QUOTA_ADJUST_QUNIT;
 extern const struct req_msg_field RMF_QUNIT_DATA;
 extern const struct req_msg_field RMF_STRING;
 
index 00c20d2..24d2a41 100644 (file)
@@ -779,5 +779,14 @@ int bulk_csum_svc(struct ptlrpc_bulk_desc *desc, int read,
                   struct ptlrpc_bulk_sec_desc *bsdv, int vsize,
                   struct ptlrpc_bulk_sec_desc *bsdr, int rsize);
 
+#define CFS_CAP_CHOWN_MASK (1 << CFS_CAP_CHOWN)
+#define CFS_CAP_SYS_RESOURCE_MASK (1 << CFS_CAP_SYS_RESOURCE)
+
+enum {
+        LUSTRE_SEC_NONE         = 0,
+        LUSTRE_SEC_REMOTE       = 1,
+        LUSTRE_SEC_SPECIFY      = 2,
+        LUSTRE_SEC_ALL          = 3
+};
 
 #endif /* _LUSTRE_SEC_H_ */
index c2fc95c..ecc92dc 100644 (file)
@@ -62,7 +62,7 @@
 struct md_device;
 struct md_device_operations;
 struct md_object;
-
+struct obd_export;
 
 enum {
         UCRED_INVALID   = -1,
@@ -73,18 +73,18 @@ enum {
 
 struct md_ucred {
         __u32               mu_valid;
-        __u32                   mu_o_uid;
-        __u32                   mu_o_gid;
-        __u32                   mu_o_fsuid;
-        __u32                   mu_o_fsgid;
-        __u32                   mu_uid;
-        __u32                   mu_gid;
-        __u32                   mu_fsuid;
-        __u32                   mu_fsgid;
-        __u32                   mu_suppgids[2];
-        cfs_cap_t               mu_cap;
-        __u32                   mu_umask;
-       struct group_info      *mu_ginfo;
+        __u32               mu_o_uid;
+        __u32               mu_o_gid;
+        __u32               mu_o_fsuid;
+        __u32               mu_o_fsgid;
+        __u32               mu_uid;
+        __u32               mu_gid;
+        __u32               mu_fsuid;
+        __u32               mu_fsgid;
+        __u32               mu_suppgids[2];
+        cfs_cap_t           mu_cap;
+        __u32               mu_umask;
+       struct group_info  *mu_ginfo;
        struct md_identity *mu_identity;
 };
 
@@ -95,6 +95,8 @@ enum {
 /** there are at most 5 fids in one operation, see rename, NOTE the last one
  * is a temporary one used for is_subdir() */
 struct md_capainfo {
+        __u32                   mc_auth;
+        __u32                   mc_padding;
         const struct lu_fid    *mc_fid[MD_CAPAINFO_MAX];
         struct lustre_capa     *mc_capa[MD_CAPAINFO_MAX];
 };
@@ -315,6 +317,82 @@ struct md_device_operations {
         int (*mdo_update_capa_key)(const struct lu_env *env,
                                    struct md_device *m,
                                    struct lustre_capa_key *key);
+
+#ifdef HAVE_QUOTA_SUPPORT
+        struct md_quota_operations {
+                int (*mqo_notify)(const struct lu_env *env,
+                                  struct md_device *m);
+
+                int (*mqo_setup)(const struct lu_env *env,
+                                 struct md_device *m,
+                                 void *data);
+
+                int (*mqo_cleanup)(const struct lu_env *env,
+                                   struct md_device *m);
+
+                int (*mqo_recovery)(const struct lu_env *env,
+                                    struct md_device *m);
+
+                int (*mqo_check)(const struct lu_env *env,
+                                 struct md_device *m,
+                                 struct obd_export *exp,
+                                 __u32 type);
+
+                int (*mqo_on)(const struct lu_env *env,
+                              struct md_device *m,
+                              __u32 type,
+                              __u32 id);
+
+                int (*mqo_off)(const struct lu_env *env,
+                               struct md_device *m,
+                               __u32 type,
+                               __u32 id);
+
+                int (*mqo_setinfo)(const struct lu_env *env,
+                                   struct md_device *m,
+                                   __u32 type,
+                                   __u32 id,
+                                   struct obd_dqinfo *dqinfo);
+
+                int (*mqo_getinfo)(const struct lu_env *env,
+                                   const struct md_device *m,
+                                   __u32 type,
+                                   __u32 id,
+                                   struct obd_dqinfo *dqinfo);
+
+                int (*mqo_setquota)(const struct lu_env *env,
+                                    struct md_device *m,
+                                    __u32 type,
+                                    __u32 id,
+                                    struct obd_dqblk *dqblk);
+
+                int (*mqo_getquota)(const struct lu_env *env,
+                                    const struct md_device *m,
+                                    __u32 type,
+                                    __u32 id,
+                                    struct obd_dqblk *dqblk);
+
+                int (*mqo_getoinfo)(const struct lu_env *env,
+                                    const struct md_device *m,
+                                    __u32 type,
+                                    __u32 id,
+                                    struct obd_dqinfo *dqinfo);
+
+                int (*mqo_getoquota)(const struct lu_env *env,
+                                     const struct md_device *m,
+                                     __u32 type,
+                                     __u32 id,
+                                     struct obd_dqblk *dqblk);
+
+                int (*mqo_invalidate)(const struct lu_env *env,
+                                      struct md_device *m,
+                                      __u32 type);
+
+                int (*mqo_finvalidate)(const struct lu_env *env,
+                                       struct md_device *m,
+                                       __u32 type);
+        } mdo_quota;
+#endif
 };
 
 enum md_upcall_event {
index 15d4273..2a5b2d8 100644 (file)
@@ -248,6 +248,8 @@ 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;
+        struct rw_semaphore       obt_rwsem;
 };
 
 /* llog contexts */
@@ -362,6 +364,7 @@ struct filter_obd {
         struct list_head         fo_capa_keys;
         struct hlist_head       *fo_capa_hash;
         struct llog_commit_master *fo_lcm;
+        int                      fo_sec_level;
 };
 
 #define OSC_MAX_RIF_DEFAULT       8
@@ -517,9 +520,9 @@ struct mds_obd {
         __u32                            mds_id;
 
         /* mark pages dirty for write. */
-        bitmap_t                         *mds_lov_page_dirty;
+        bitmap_t                        *mds_lov_page_dirty;
         /* array for store pages with obd_id */
-        void                            **mds_lov_page_array;
+        void                           **mds_lov_page_array;
         /* file for store objid */
         struct file                     *mds_lov_objid_filp;
         __u32                            mds_lov_objid_count;
@@ -537,13 +540,14 @@ struct mds_obd {
                                          mds_fl_acl:1,
                                          mds_evict_ost_nids:1,
                                          mds_fl_cfglog:1,
-                                         mds_fl_synced:1;
+                                         mds_fl_synced:1,
+                                         mds_quota:1;
 
         struct upcall_cache             *mds_identity_cache;
 
         /* for capability keys update */
         struct lustre_capa_key          *mds_capa_keys;
-        struct rw_semaphore             mds_notify_lock;
+        struct rw_semaphore              mds_notify_lock;
 };
 
 /* lov objid */
@@ -788,7 +792,7 @@ struct obd_trans_info {
         int                      oti_numcookies;
 
         /* initial thread handling transaction */
-        int                      oti_thread_id;
+        struct ptlrpc_thread *   oti_thread;
         __u32                    oti_conn_cnt;
 
         struct obd_uuid         *oti_ost_uuid;
@@ -808,7 +812,7 @@ static inline void oti_init(struct obd_trans_info *oti,
 
         if (req->rq_repmsg != NULL)
                 oti->oti_transno = lustre_msg_get_transno(req->rq_repmsg);
-        oti->oti_thread_id = req->rq_svc_thread ? req->rq_svc_thread->t_id : -1;
+        oti->oti_thread = req->rq_svc_thread;
         if (req->rq_reqmsg != NULL)
                 oti->oti_conn_cnt = lustre_msg_get_conn_cnt(req->rq_reqmsg);
 }
@@ -1214,7 +1218,7 @@ struct obd_ops {
                         struct lov_stripe_md **ea, struct obd_trans_info *oti);
         int (*o_destroy)(struct obd_export *exp, struct obdo *oa,
                          struct lov_stripe_md *ea, struct obd_trans_info *oti,
-                         struct obd_export *md_exp);
+                         struct obd_export *md_exp, void *capa);
         int (*o_setattr)(struct obd_export *exp, struct obd_info *oinfo,
                          struct obd_trans_info *oti);
         int (*o_setattr_async)(struct obd_export *exp, struct obd_info *oinfo,
@@ -1292,8 +1296,14 @@ struct obd_ops {
         struct obd_uuid *(*o_get_uuid) (struct obd_export *exp);
 
         /* quota methods */
-        int (*o_quotacheck)(struct obd_export *, struct obd_quotactl *);
-        int (*o_quotactl)(struct obd_export *, struct obd_quotactl *);
+        int (*o_quotacheck)(struct obd_device *, struct obd_export *,
+                            struct obd_quotactl *);
+        int (*o_quotactl)(struct obd_device *, struct obd_export *,
+                          struct obd_quotactl *);
+        int (*o_quota_adjust_qunit)(struct obd_export *exp,
+                                    struct quota_adjust_qunit *oqaq,
+                                    struct lustre_quota_ctxt *qctxt);
+
 
         int (*o_ping)(struct obd_export *exp);
 
@@ -1436,6 +1446,8 @@ struct md_ops {
                                void *opaque);
         int (*m_renew_capa)(struct obd_export *, struct obd_capa *oc,
                             renew_capa_cb_t cb);
+        int (*m_unpack_capa)(struct obd_export *, struct ptlrpc_request *,
+                             const struct req_msg_field *, struct obd_capa **);
 
         int (*m_get_remote_perm)(struct obd_export *, const struct lu_fid *,
                                  struct obd_capa *, __u32,
@@ -1526,6 +1538,7 @@ static inline void init_obd_quota_ops(quota_interface_t *interface,
         LASSERT(obd_ops);
         obd_ops->o_quotacheck = QUOTA_OP(interface, check);
         obd_ops->o_quotactl = QUOTA_OP(interface, ctl);
+        obd_ops->o_quota_adjust_qunit = QUOTA_OP(interface, adjust_qunit);
 }
 
 static inline __u64 oinfo_mdsno(struct obd_info *oinfo)
index 3e885b2..8fe3e6c 100644 (file)
@@ -86,8 +86,6 @@ void class_obd_list(void);
 struct obd_device * class_find_client_obd(struct obd_uuid *tgt_uuid,
                                           const char * typ_name,
                                           struct obd_uuid *grp_uuid);
-struct obd_device * class_find_client_notype(struct obd_uuid *tgt_uuid,
-                                             struct obd_uuid *grp_uuid);
 struct obd_device * class_devices_in_group(struct obd_uuid *grp_uuid,
                                            int *next);
 struct obd_device * class_num2obd(int num);
@@ -669,7 +667,7 @@ static inline int obd_create(struct obd_export *exp, struct obdo *obdo,
 static inline int obd_destroy(struct obd_export *exp, struct obdo *obdo,
                               struct lov_stripe_md *ea,
                               struct obd_trans_info *oti,
-                              struct obd_export *md_exp)
+                              struct obd_export *md_exp, void *capa)
 {
         int rc;
         ENTRY;
@@ -677,7 +675,7 @@ static inline int obd_destroy(struct obd_export *exp, struct obdo *obdo,
         EXP_CHECK_DT_OP(exp, destroy);
         EXP_COUNTER_INCREMENT(exp, destroy);
 
-        rc = OBP(exp->exp_obd, destroy)(exp, obdo, ea, oti, md_exp);
+        rc = OBP(exp->exp_obd, destroy)(exp, obdo, ea, oti, md_exp, capa);
         RETURN(rc);
 }
 
@@ -1469,7 +1467,7 @@ static inline int obd_quotacheck(struct obd_export *exp,
         EXP_CHECK_DT_OP(exp, quotacheck);
         EXP_COUNTER_INCREMENT(exp, quotacheck);
 
-        rc = OBP(exp->exp_obd, quotacheck)(exp, oqctl);
+        rc = OBP(exp->exp_obd, quotacheck)(exp->exp_obd, exp, oqctl);
         RETURN(rc);
 }
 
@@ -1482,7 +1480,39 @@ static inline int obd_quotactl(struct obd_export *exp,
         EXP_CHECK_DT_OP(exp, quotactl);
         EXP_COUNTER_INCREMENT(exp, quotactl);
 
-        rc = OBP(exp->exp_obd, quotactl)(exp, oqctl);
+        rc = OBP(exp->exp_obd, quotactl)(exp->exp_obd, exp, oqctl);
+        RETURN(rc);
+}
+
+static inline int obd_quota_adjust_qunit(struct obd_export *exp,
+                                         struct quota_adjust_qunit *oqaq,
+                                         struct lustre_quota_ctxt *qctxt)
+{
+#if defined(LPROCFS) && defined(HAVE_QUOTA_SUPPORT)
+        struct timeval work_start;
+        struct timeval work_end;
+        long timediff;
+#endif
+        int rc;
+        ENTRY;
+
+#if defined(LPROCFS) && defined(HAVE_QUOTA_SUPPORT)
+        if (qctxt)
+                do_gettimeofday(&work_start);
+#endif
+        EXP_CHECK_DT_OP(exp, quota_adjust_qunit);
+        EXP_COUNTER_INCREMENT(exp, quota_adjust_qunit);
+
+        rc = OBP(exp->exp_obd, quota_adjust_qunit)(exp, oqaq, qctxt);
+
+#if defined(LPROCFS) && defined(HAVE_QUOTA_SUPPORT)
+        if (qctxt) {
+                do_gettimeofday(&work_end);
+                timediff = cfs_timeval_sub(&work_end, &work_start, NULL);
+                lprocfs_counter_add(qctxt->lqc_stats, LQUOTA_ADJUST_QUNIT,
+                                    timediff);
+        }
+#endif
         RETURN(rc);
 }
 
@@ -1932,6 +1962,19 @@ static inline int md_renew_capa(struct obd_export *exp, struct obd_capa *ocapa,
         RETURN(rc);
 }
 
+static inline int md_unpack_capa(struct obd_export *exp,
+                                 struct ptlrpc_request *req,
+                                 const struct req_msg_field *field,
+                                 struct obd_capa **oc)
+{
+        int rc;
+        ENTRY;
+        EXP_CHECK_MD_OP(exp, unpack_capa);
+        EXP_MD_COUNTER_INCREMENT(exp, unpack_capa);
+        rc = MDP(exp->exp_obd, unpack_capa)(exp, req, field, oc);
+        RETURN(rc);
+}
+
 static inline int md_intent_getattr_async(struct obd_export *exp,
                                           struct md_enqueue_info *minfo,
                                           struct ldlm_enqueue_info *einfo)
index b849ff0..8ddb969 100644 (file)
@@ -54,6 +54,7 @@ struct osc_brw_async_args {
         struct brw_page  **aa_ppga;
         struct client_obd *aa_cli;
         struct list_head   aa_oaps;
+        struct obd_capa   *aa_ocapa;
         struct cl_req     *aa_clerq;
 };
 
index 25ab060..50379c5 100644 (file)
@@ -192,6 +192,8 @@ int obd_alloc_fail(const void *ptr, const char *name, const char *type,
 #define OBD_FAIL_MDS_CLOSE_NET_REP       0x13f
 #define OBD_FAIL_MDS_LLOG_SYNC_TIMEOUT   0x140
 #define OBD_FAIL_MDS_RECOVERY_ACCEPTS_GAPS 0x141
+#define OBD_FAIL_MDS_BLOCK_QUOTA_REQ     0x142
+#define OBD_FAIL_MDS_DROP_QUOTA_REQ      0x143
 
 #define OBD_FAIL_OST                     0x200
 #define OBD_FAIL_OST_CONNECT_NET         0x201
@@ -320,7 +322,7 @@ int obd_alloc_fail(const void *ptr, const char *name, const char *type,
 #define OBD_FAIL_MGS_PAUSE_REQ           0x904
 #define OBD_FAIL_MGS_PAUSE_TARGET_REG    0x905
 
-#define OBD_FAIL_QUOTA_QD_COUNT_32BIT    0xA00
+#define OBD_FAIL_QUOTA_RET_QDATA         0xA02
 
 #define OBD_FAIL_LPROC_REMOVE            0xB00
 
diff --git a/lustre/kernel_patches/patches/quota-fix-oops-in-invalidate_dquots.patch b/lustre/kernel_patches/patches/quota-fix-oops-in-invalidate_dquots.patch
new file mode 100644 (file)
index 0000000..b8c6b0d
--- /dev/null
@@ -0,0 +1,127 @@
+From: Jan Kara <jack@suse.cz>
+Date: Thu, 23 Mar 2006 11:00:17 +0000 (-0800)
+Subject: [PATCH] Fix oops in invalidate_dquots()
+X-Git-Tag: v2.6.17-rc1~1059
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=6362e4d4eda61efb04ac1cdae32e48ac6d90b701
+
+[PATCH] Fix oops in invalidate_dquots()
+
+When quota is being turned off we assumed that all the references to dquots
+were already dropped.  That need not be true as inodes being deleted are
+not on superblock's inodes list and hence we need not reach it when
+removing quota references from inodes.  So invalidate_dquots() has to wait
+for all the users of dquots (as quota is already marked as turned off, no
+new references can be acquired and so this is bound to happen rather
+early).  When we do this, we can also remove the iprune_sem locking as it
+was protecting us against exactly the same problem when freeing inodes
+icache memory.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Andrew Morton <akpm@osdl.org>
+Signed-off-by: Linus Torvalds <torvalds@osdl.org>
+---
+
+diff --git a/fs/dquot.c b/fs/dquot.c
+index 1966c89..9376a43 100644
+--- a/fs/dquot.c
++++ b/fs/dquot.c
+@@ -118,8 +118,7 @@
+  * spinlock to internal buffers before writing.
+  *
+  * Lock ordering (including related VFS locks) is the following:
+- *   i_mutex > dqonoff_sem > iprune_sem > journal_lock > dqptr_sem >
+- *   > dquot->dq_lock > dqio_sem
++ *  i_mutex > dqonoff_sem > journal_lock > dqptr_sem > dquot->dq_lock > dqio_sem
+  * i_mutex on quota files is special (it's below dqio_sem)
+  */
+@@ -407,23 +406,49 @@ out_dqlock:
+ /* Invalidate all dquots on the list. Note that this function is called after
+  * quota is disabled and pointers from inodes removed so there cannot be new
+- * quota users. Also because we hold dqonoff_sem there can be no quota users
+- * for this sb+type at all. */
++ * quota users. There can still be some users of quotas due to inodes being
++ * just deleted or pruned by prune_icache() (those are not attached to any
++ * list). We have to wait for such users.
++ */
+ static void invalidate_dquots(struct super_block *sb, int type)
+ {
+       struct dquot *dquot, *tmp;
++restart:
+       spin_lock(&dq_list_lock);
+       list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) {
+               if (dquot->dq_sb != sb)
+                       continue;
+               if (dquot->dq_type != type)
+                       continue;
+-#ifdef __DQUOT_PARANOIA
+-              if (atomic_read(&dquot->dq_count))
+-                      BUG();
+-#endif
+-              /* Quota now has no users and it has been written on last dqput() */
++              /* Wait for dquot users */
++              if (atomic_read(&dquot->dq_count)) {
++                      DEFINE_WAIT(wait);
++
++                      atomic_inc(&dquot->dq_count);
++                      prepare_to_wait(&dquot->dq_wait_unused, &wait,
++                                      TASK_UNINTERRUPTIBLE);
++                      spin_unlock(&dq_list_lock);
++                      /* Once dqput() wakes us up, we know it's time to free
++                       * the dquot.
++                       * IMPORTANT: we rely on the fact that there is always
++                       * at most one process waiting for dquot to free.
++                       * Otherwise dq_count would be > 1 and we would never
++                       * wake up.
++                       */
++                      if (atomic_read(&dquot->dq_count) > 1)
++                              schedule();
++                      finish_wait(&dquot->dq_wait_unused, &wait);
++                      dqput(dquot);
++                      /* At this moment dquot() need not exist (it could be
++                       * reclaimed by prune_dqcache(). Hence we must
++                       * restart. */
++                      goto restart;
++              }
++              /*
++               * Quota now has no users and it has been written on last
++               * dqput()
++               */
+               remove_dquot_hash(dquot);
+               remove_free_dquot(dquot);
+               remove_inuse(dquot);
+@@ -540,6 +565,10 @@ we_slept:
+       if (atomic_read(&dquot->dq_count) > 1) {
+               /* We have more than one user... nothing to do */
+               atomic_dec(&dquot->dq_count);
++              /* Releasing dquot during quotaoff phase? */
++              if (!sb_has_quota_enabled(dquot->dq_sb, dquot->dq_type) &&
++                  atomic_read(&dquot->dq_count) == 1)
++                      wake_up(&dquot->dq_wait_unused);
+               spin_unlock(&dq_list_lock);
+               return;
+       }
+@@ -581,6 +610,7 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
+       INIT_LIST_HEAD(&dquot->dq_inuse);
+       INIT_HLIST_NODE(&dquot->dq_hash);
+       INIT_LIST_HEAD(&dquot->dq_dirty);
++      init_waitqueue_head(&dquot->dq_wait_unused);
+       dquot->dq_sb = sb;
+       dquot->dq_type = type;
+       atomic_set(&dquot->dq_count, 1);
+@@ -732,13 +762,9 @@ static void drop_dquot_ref(struct super_block *sb, int type)
+ {
+       LIST_HEAD(tofree_head);
+-      /* We need to be guarded against prune_icache to reach all the
+-       * inodes - otherwise some can be on the local list of prune_icache */
+-      down(&iprune_sem);
+       down_write(&sb_dqopt(sb)->dqptr_sem);
+       remove_dquot_ref(sb, type, &tofree_head);
+       up_write(&sb_dqopt(sb)->dqptr_sem);
+-      up(&iprune_sem);
+       put_dquot_list(&tofree_head);
+ }
diff --git a/lustre/kernel_patches/patches/quota-large-limits-rhel5.patch b/lustre/kernel_patches/patches/quota-large-limits-rhel5.patch
new file mode 100644 (file)
index 0000000..4f3a3bc
--- /dev/null
@@ -0,0 +1,616 @@
+diff -rNpu linux-2.6.16.54-0.2.5/fs/dquot.c linux-2.6.16.54-0.2.5-quota/fs/dquot.c
+--- linux-2.6.16.54-0.2.5/fs/dquot.c   2008-03-18 15:48:26.000000000 +0300
++++ linux-2.6.16.54-0.2.5-quota/fs/dquot.c     2008-03-17 22:43:11.000000000 +0300
+@@ -1588,10 +1588,19 @@ int vfs_get_dqblk(struct super_block *sb
+ }
+ /* Generic routine for setting common part of quota structure */
+-static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
++static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
+ {
+       struct mem_dqblk *dm = &dquot->dq_dqb;
+       int check_blim = 0, check_ilim = 0;
++      struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
++
++      if ((di->dqb_valid & QIF_BLIMITS &&
++           (di->dqb_bhardlimit > dqi->dqi_maxblimit ||
++            di->dqb_bsoftlimit > dqi->dqi_maxblimit)) ||
++          (di->dqb_valid & QIF_ILIMITS &&
++           (di->dqb_ihardlimit > dqi->dqi_maxilimit ||
++            di->dqb_isoftlimit > dqi->dqi_maxilimit)))
++              return -ERANGE;
+       spin_lock(&dq_data_lock);
+       if (di->dqb_valid & QIF_SPACE) {
+@@ -1623,7 +1632,7 @@ static void do_set_dqblk(struct dquot *d
+                       clear_bit(DQ_BLKS_B, &dquot->dq_flags);
+               }
+               else if (!(di->dqb_valid & QIF_BTIME))  /* Set grace only if user hasn't provided his own... */
+-                      dm->dqb_btime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace;
++                      dm->dqb_btime = get_seconds() + dqi->dqi_bgrace;
+       }
+       if (check_ilim) {
+               if (!dm->dqb_isoftlimit || dm->dqb_curinodes < dm->dqb_isoftlimit) {
+@@ -1631,7 +1640,7 @@ static void do_set_dqblk(struct dquot *d
+                       clear_bit(DQ_INODES_B, &dquot->dq_flags);
+               }
+               else if (!(di->dqb_valid & QIF_ITIME))  /* Set grace only if user hasn't provided his own... */
+-                      dm->dqb_itime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
++                      dm->dqb_itime = get_seconds() + dqi->dqi_igrace;
+       }
+       if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || dm->dqb_isoftlimit)
+               clear_bit(DQ_FAKE_B, &dquot->dq_flags);
+@@ -1639,21 +1648,24 @@ static void do_set_dqblk(struct dquot *d
+               set_bit(DQ_FAKE_B, &dquot->dq_flags);
+       spin_unlock(&dq_data_lock);
+       mark_dquot_dirty(dquot);
++
++      return 0;
+ }
+ int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di)
+ {
+       struct dquot *dquot;
++      int rc;
+       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
+       if (!(dquot = dqget(sb, id, type))) {
+               mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
+               return -ESRCH;
+       }
+-      do_set_dqblk(dquot, di);
++      rc = do_set_dqblk(dquot, di);
+       dqput(dquot);
+       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
+-      return 0;
++      return rc;
+ }
+ /* Generic routine for getting common part of quota file information */
+diff -rNpu linux-2.6.16.54-0.2.5/fs/quota_v1.c linux-2.6.16.54-0.2.5-quota/fs/quota_v1.c
+--- linux-2.6.16.54-0.2.5/fs/quota_v1.c        2006-03-20 08:53:29.000000000 +0300
++++ linux-2.6.16.54-0.2.5-quota/fs/quota_v1.c  2008-03-17 22:42:47.000000000 +0300
+@@ -139,6 +139,9 @@ static int v1_read_file_info(struct supe
+               goto out;
+       }
+       ret = 0;
++      /* limits are stored as unsigned 32-bit data */
++      dqopt->info[type].dqi_maxblimit = 0xffffffff;
++      dqopt->info[type].dqi_maxilimit = 0xffffffff;
+       dqopt->info[type].dqi_igrace = dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME;
+       dqopt->info[type].dqi_bgrace = dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME;
+ out:
+diff -rNpu linux-2.6.16.54-0.2.5/fs/quota_v2.c linux-2.6.16.54-0.2.5-quota/fs/quota_v2.c
+--- linux-2.6.16.54-0.2.5/fs/quota_v2.c        2006-03-20 08:53:29.000000000 +0300
++++ linux-2.6.16.54-0.2.5-quota/fs/quota_v2.c  2008-03-18 11:58:02.000000000 +0300
+@@ -23,26 +23,64 @@ MODULE_LICENSE("GPL");
+ typedef char *dqbuf_t;
+ #define GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff)
+-#define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader)))
++#define GETENTRIES(buf) ((union v2_disk_dqblk *)(((char *)buf) + \
++                       sizeof(struct v2_disk_dqdbheader)))
++#define REV_ASSERT(r) BUG_ON((rev) != 0 && (rev) != 1)
++
++static const union v2_disk_dqblk emptydquot;
++static const union v2_disk_dqblk fakedquot[2] = {
++      {.r0 = {.dqb_itime = __constant_cpu_to_le64(1LLU)} },
++      {.r1 = {.dqb_itime = __constant_cpu_to_le64(1LLU)} }
++};
+-/* Check whether given file is really vfsv0 quotafile */
+-static int v2_check_quota_file(struct super_block *sb, int type)
++static inline uint v2_dqblksz(uint rev)
++{
++      uint sz;
++
++      REV_ASSERT(rev);
++
++      if (rev == 0)
++              sz = sizeof(struct v2_disk_dqblk_r0);
++      else
++              sz = sizeof(struct v2_disk_dqblk_r1);
++
++      return sz;
++}
++
++/* Number of quota entries in a block */
++static inline int v2_dqstrinblk(uint rev)
++{
++      return (V2_DQBLKSIZE-sizeof(struct v2_disk_dqdbheader))/v2_dqblksz(rev);
++}
++
++/* Get revision of a quota file, -1 if it does not look a quota file */
++static int v2_quota_file_revision(struct super_block *sb, int type)
+ {
+       struct v2_disk_dqheader dqhead;
+       ssize_t size;
+       static const uint quota_magics[] = V2_INITQMAGICS;
+-      static const uint quota_versions[] = V2_INITQVERSIONS;
++      static const uint quota_versions_r0[] = V2_INITQVERSIONS_R0;
++      static const uint quota_versions_r1[] = V2_INITQVERSIONS_R1;
+  
+       size = sb->s_op->quota_read(sb, type, (char *)&dqhead, sizeof(struct v2_disk_dqheader), 0);
+       if (size != sizeof(struct v2_disk_dqheader)) {
+               printk("quota_v2: failed read expected=%zd got=%zd\n",
+                       sizeof(struct v2_disk_dqheader), size);
+-              return 0;
++              return -1;
+       }
+-      if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
+-          le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
+-              return 0;
+-      return 1;
++      if (le32_to_cpu(dqhead.dqh_magic) == quota_magics[type]) {
++              if (le32_to_cpu(dqhead.dqh_version) == quota_versions_r0[type])
++                      return 0;
++              if (le32_to_cpu(dqhead.dqh_version) == quota_versions_r1[type])
++                      return 1;
++      }
++      return -1;
++}
++
++/* Check whether given file is really vfsv0 quotafile */
++static inline int v2_check_quota_file(struct super_block *sb, int type)
++{
++      return v2_quota_file_revision(sb, type) != -1;
+ }
+ /* Read information header from quota file */
+@@ -51,6 +89,13 @@ static int v2_read_file_info(struct supe
+       struct v2_disk_dqinfo dinfo;
+       struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
+       ssize_t size;
++      int rev;
++
++      rev = v2_quota_file_revision(sb, type);
++      if (rev < 0) {
++              printk(KERN_WARNING "Second quota file check failed.\n");
++              return -1;
++      }
+       size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
+              sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
+@@ -65,6 +110,16 @@ static int v2_read_file_info(struct supe
+       info->u.v2_i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
+       info->u.v2_i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
+       info->u.v2_i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
++
++      info->u.v2_i.dqi_revision = rev;
++      if (rev == 0) {
++              info->dqi_maxblimit = 0xffffffffULL;
++              info->dqi_maxilimit = 0xffffffffULL;
++      } else {
++              info->dqi_maxblimit = 0xffffffffffffffffULL;
++              info->dqi_maxilimit = 0xffffffffffffffffULL;
++      }
++
+       return 0;
+ }
+@@ -94,29 +149,61 @@ static int v2_write_file_info(struct sup
+       return 0;
+ }
+-static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d)
++static void disk2memdqb(struct mem_dqblk *m, union v2_disk_dqblk *d, uint rev)
+ {
+-      m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
+-      m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
+-      m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
+-      m->dqb_itime = le64_to_cpu(d->dqb_itime);
+-      m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit);
+-      m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit);
+-      m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
+-      m->dqb_btime = le64_to_cpu(d->dqb_btime);
+-}
+-
+-static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
+-{
+-      d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
+-      d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
+-      d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
+-      d->dqb_itime = cpu_to_le64(m->dqb_itime);
+-      d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit);
+-      d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit);
+-      d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
+-      d->dqb_btime = cpu_to_le64(m->dqb_btime);
+-      d->dqb_id = cpu_to_le32(id);
++      REV_ASSERT(rev);
++
++      if (rev == 0) {
++              struct v2_disk_dqblk_r0 *ddqblk = &d->r0;
++              m->dqb_ihardlimit = le32_to_cpu(ddqblk->dqb_ihardlimit);
++              m->dqb_isoftlimit = le32_to_cpu(ddqblk->dqb_isoftlimit);
++              m->dqb_curinodes = le32_to_cpu(ddqblk->dqb_curinodes);
++              m->dqb_itime = le64_to_cpu(ddqblk->dqb_itime);
++              m->dqb_bhardlimit = le32_to_cpu(ddqblk->dqb_bhardlimit);
++              m->dqb_bsoftlimit = le32_to_cpu(ddqblk->dqb_bsoftlimit);
++              m->dqb_curspace = le64_to_cpu(ddqblk->dqb_curspace);
++              m->dqb_btime = le64_to_cpu(ddqblk->dqb_btime);
++      } else {
++              struct v2_disk_dqblk_r1 *ddqblk = &d->r1;
++              m->dqb_ihardlimit = le64_to_cpu(ddqblk->dqb_ihardlimit);
++              m->dqb_isoftlimit = le64_to_cpu(ddqblk->dqb_isoftlimit);
++              m->dqb_curinodes = le64_to_cpu(ddqblk->dqb_curinodes);
++              m->dqb_itime = le64_to_cpu(ddqblk->dqb_itime);
++              m->dqb_bhardlimit = le64_to_cpu(ddqblk->dqb_bhardlimit);
++              m->dqb_bsoftlimit = le64_to_cpu(ddqblk->dqb_bsoftlimit);
++              m->dqb_curspace = le64_to_cpu(ddqblk->dqb_curspace);
++              m->dqb_btime = le64_to_cpu(ddqblk->dqb_btime);
++      }
++}
++
++static void mem2diskdqb(union v2_disk_dqblk *d, struct mem_dqblk *m,
++                      qid_t id, uint rev)
++{
++      REV_ASSERT(rev);
++
++      if (rev == 0) {
++              struct v2_disk_dqblk_r0 *ddqblk = &d->r0;
++              ddqblk->dqb_id = cpu_to_le32(id);
++              ddqblk->dqb_ihardlimit = cpu_to_le32((__u32)m->dqb_ihardlimit);
++              ddqblk->dqb_isoftlimit = cpu_to_le32((__u32)m->dqb_isoftlimit);
++              ddqblk->dqb_curinodes = cpu_to_le32((__u32)m->dqb_curinodes);
++              ddqblk->dqb_itime = cpu_to_le64(m->dqb_itime);
++              ddqblk->dqb_bhardlimit = cpu_to_le32((__u32)m->dqb_bhardlimit);
++              ddqblk->dqb_bsoftlimit = cpu_to_le32((__u32)m->dqb_bsoftlimit);
++              ddqblk->dqb_curspace = cpu_to_le64(m->dqb_curspace);
++              ddqblk->dqb_btime = cpu_to_le64(ddqblk->dqb_btime);
++      } else {
++              struct v2_disk_dqblk_r1 *ddqblk = &d->r1;
++              ddqblk->dqb_id = cpu_to_le32(id);
++              ddqblk->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
++              ddqblk->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
++              ddqblk->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
++              ddqblk->dqb_itime = cpu_to_le64(m->dqb_itime);
++              ddqblk->dqb_bhardlimit = cpu_to_le64(m->dqb_bhardlimit);
++              ddqblk->dqb_bsoftlimit = cpu_to_le64(m->dqb_bsoftlimit);
++              ddqblk->dqb_curspace = cpu_to_le64(m->dqb_curspace);
++              ddqblk->dqb_btime = cpu_to_le64(ddqblk->dqb_btime);
++      }
+ }
+ static dqbuf_t getdqbuf(void)
+@@ -268,10 +355,10 @@ static uint find_free_dqentry(struct dqu
+ {
+       struct super_block *sb = dquot->dq_sb;
+       struct mem_dqinfo *info = sb_dqopt(sb)->info+dquot->dq_type;
+-      uint blk, i;
++      uint blk, i, rev = info->u.v2_i.dqi_revision;
++      uint dqblksz = v2_dqblksz(rev), dqstrinblk = v2_dqstrinblk(rev);
+       struct v2_disk_dqdbheader *dh;
+-      struct v2_disk_dqblk *ddquot;
+-      struct v2_disk_dqblk fakedquot;
++      union v2_disk_dqblk *ddquot;
+       dqbuf_t buf;
+       *err = 0;
+@@ -298,17 +385,18 @@ static uint find_free_dqentry(struct dqu
+               info->u.v2_i.dqi_free_entry = blk;
+               mark_info_dirty(sb, dquot->dq_type);
+       }
+-      if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK)   /* Block will be full? */
++      /* Block will be full? */
++      if (le16_to_cpu(dh->dqdh_entries)+1 >= dqstrinblk)
+               if ((*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) {
+                       printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
+                       goto out_buf;
+               }
+       dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)+1);
+-      memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
+       /* Find free structure in block */
+-      for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++);
++      for (i = 0; i < dqstrinblk && memcmp(&emptydquot, ddquot, dqblksz);
++           i++, ddquot = (char *)ddquot + dqblksz);
+ #ifdef __QUOTA_V2_PARANOIA
+-      if (i == V2_DQSTRINBLK) {
++      if (i == dqstrinblk) {
+               printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
+               *err = -EIO;
+               goto out_buf;
+@@ -318,7 +406,8 @@ static uint find_free_dqentry(struct dqu
+               printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
+               goto out_buf;
+       }
+-      dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+sizeof(struct v2_disk_dqdbheader)+i*sizeof(struct v2_disk_dqblk);
++      dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+
++                      ((char *)ddquot - (char *)buf);
+       freedqbuf(buf);
+       return blk;
+ out_buf:
+@@ -392,7 +481,9 @@ static int v2_write_dquot(struct dquot *
+ {
+       int type = dquot->dq_type;
+       ssize_t ret;
+-      struct v2_disk_dqblk ddquot, empty;
++      union v2_disk_dqblk ddquot;
++      uint rev = sb_dqopt(dquot->dq_sb)->info[type].u.v2_i.dqi_revision;
++      uint dqblksz = v2_dqblksz(rev);
+       /* dq_off is guarded by dqio_sem */
+       if (!dquot->dq_off)
+@@ -401,18 +492,22 @@ static int v2_write_dquot(struct dquot *
+                       return ret;
+               }
+       spin_lock(&dq_data_lock);
+-      mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
++      mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id, rev);
+       /* Argh... We may need to write structure full of zeroes but that would be
+        * treated as an empty place by the rest of the code. Format change would
+        * be definitely cleaner but the problems probably are not worth it */
+-      memset(&empty, 0, sizeof(struct v2_disk_dqblk));
+-      if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
+-              ddquot.dqb_itime = cpu_to_le64(1);
++      if (!memcmp(&emptydquot, &ddquot, dqblksz)) {
++              if (rev == 0)
++                      ddquot.r0.dqb_itime = cpu_to_le64(1);
++              else
++                      ddquot.r1.dqb_itime = cpu_to_le64(1);
++      }
+       spin_unlock(&dq_data_lock);
+       ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
+-            (char *)&ddquot, sizeof(struct v2_disk_dqblk), dquot->dq_off);
+-      if (ret != sizeof(struct v2_disk_dqblk)) {
+-              printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id);
++            (char *)&ddquot, dqblksz, dquot->dq_off);
++      if (ret != dqblksz) {
++              printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
++                      dquot->dq_sb->s_id);
+               if (ret >= 0)
+                       ret = -ENOSPC;
+       }
+@@ -431,6 +526,7 @@ static int free_dqentry(struct dquot *dq
+       struct v2_disk_dqdbheader *dh;
+       dqbuf_t buf = getdqbuf();
+       int ret = 0;
++      uint rev = sb_dqopt(sb)->info[type].u.v2_i.dqi_revision;
+       if (!buf)
+               return -ENOMEM;
+@@ -456,8 +552,8 @@ static int free_dqentry(struct dquot *dq
+       }
+       else {
+               memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0,
+-                sizeof(struct v2_disk_dqblk));
+-              if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
++                v2_dqblksz(rev));
++              if (le16_to_cpu(dh->dqdh_entries) == v2_dqstrinblk(rev)-1) {
+                       /* Insert will write block itself */
+                       if ((ret = insert_free_dqentry(sb, type, buf, blk)) < 0) {
+                               printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
+@@ -529,41 +625,56 @@ static int v2_delete_dquot(struct dquot 
+       return remove_tree(dquot, &tmp, 0);
+ }
++static inline __u32 dqid(union v2_disk_dqblk *ddquot, uint rev)
++{
++      __u32 dq_id;
++
++      REV_ASSERT(rev);
++
++      if (rev == 0)
++              dq_id = le32_to_cpu(ddquot->r0.dqb_id);
++      else
++              dq_id = le32_to_cpu(ddquot->r1.dqb_id);
++
++      return dq_id;
++}
++
+ /* Find entry in block */
+ static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
+ {
+       dqbuf_t buf = getdqbuf();
+       loff_t ret = 0;
+       int i;
+-      struct v2_disk_dqblk *ddquot = GETENTRIES(buf);
++      union v2_disk_dqblk *ddquot = GETENTRIES(buf);
++      int type = dquot->dq_type;
++      uint rev = sb_dqopt(dquot->dq_sb)->info[type].u.v2_i.dqi_revision;
++      uint dqblksz = v2_dqblksz(rev), dqstrinblk = v2_dqstrinblk(rev);
+       if (!buf)
+               return -ENOMEM;
+-      if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
++
++      ret = read_blk(dquot->dq_sb, type, blk, buf);
++      if (ret < 0) {
+               printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
+               goto out_buf;
+       }
+       if (dquot->dq_id)
+-              for (i = 0; i < V2_DQSTRINBLK &&
+-                   le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
++              for (i = 0; i < dqstrinblk && dqid(ddquot, rev) != dquot->dq_id;
++                   i++, ddquot = (char *)ddquot + dqblksz);
+       else {  /* ID 0 as a bit more complicated searching... */
+-              struct v2_disk_dqblk fakedquot;
+-
+-              memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
+-              for (i = 0; i < V2_DQSTRINBLK; i++)
+-                      if (!le32_to_cpu(ddquot[i].dqb_id) &&
+-                          memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
++              for (i = 0; i < dqstrinblk; i++, ddquot = (char *)ddquot+dqblksz)
++                      if (!dqid(ddquot, rev) &&
++                          memcmp(&emptydquot, ddquot, dqblksz))
+                               break;
+       }
+-      if (i == V2_DQSTRINBLK) {
++      if (i == dqstrinblk) {
+               printk(KERN_ERR "VFS: Quota for id %u referenced "
+                 "but not present.\n", dquot->dq_id);
+               ret = -EIO;
+               goto out_buf;
+       }
+       else
+-              ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct
+-                v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
++              ret = (blk << V2_DQBLKSIZE_BITS)+((char *)ddquot-(char *)buf);
+ out_buf:
+       freedqbuf(buf);
+       return ret;
+@@ -605,7 +716,7 @@ static int v2_read_dquot(struct dquot *d
+ {
+       int type = dquot->dq_type;
+       loff_t offset;
+-      struct v2_disk_dqblk ddquot, empty;
++      union v2_disk_dqblk ddquot;
+       int ret = 0;
+ #ifdef __QUOTA_V2_PARANOIA
+@@ -626,25 +737,30 @@ static int v2_read_dquot(struct dquot *d
+               ret = offset;
+       }
+       else {
++              uint rev = sb_dqopt(dquot->dq_sb)->info[type].u.v2_i.
++                         dqi_revision;
++              uint  dqblksz = v2_dqblksz(rev);
+               dquot->dq_off = offset;
+-              if ((ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
+-                  (char *)&ddquot, sizeof(struct v2_disk_dqblk), offset))
+-                  != sizeof(struct v2_disk_dqblk)) {
++              ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
++                                         (char *)&ddquot, dqblksz, offset);
++              if (ret != dqblksz) {
+                       if (ret >= 0)
+                               ret = -EIO;
+                       printk(KERN_ERR "VFS: Error while reading quota "
+                         "structure for id %u.\n", dquot->dq_id);
+-                      memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
++                      memset(&ddquot, 0, dqblksz);
+               }
+               else {
+                       ret = 0;
+                       /* We need to escape back all-zero structure */
+-                      memset(&empty, 0, sizeof(struct v2_disk_dqblk));
+-                      empty.dqb_itime = cpu_to_le64(1);
+-                      if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
+-                              ddquot.dqb_itime = 0;
++                      if (!memcmp(&fakedquot[rev], &ddquot, dqblksz)) {
++                              if (rev == 0)
++                                      ddquot.r0.dqb_itime = cpu_to_le64(0);
++                              else
++                                      ddquot.r1.dqb_itime = cpu_to_le64(0);
++                      }
+               }
+-              disk2memdqb(&dquot->dq_dqb, &ddquot);
++              disk2memdqb(&dquot->dq_dqb, &ddquot, rev);
+               if (!dquot->dq_dqb.dqb_bhardlimit &&
+                       !dquot->dq_dqb.dqb_bsoftlimit &&
+                       !dquot->dq_dqb.dqb_ihardlimit &&
+diff -rNpu linux-2.6.16.54-0.2.5/include/linux/dqblk_v2.h linux-2.6.16.54-0.2.5-quota/include/linux/dqblk_v2.h
+--- linux-2.6.16.54-0.2.5/include/linux/dqblk_v2.h     2006-03-20 08:53:29.000000000 +0300
++++ linux-2.6.16.54-0.2.5-quota/include/linux/dqblk_v2.h       2008-03-17 23:39:54.000000000 +0300
+@@ -21,6 +21,7 @@ struct v2_mem_dqinfo {
+       unsigned int dqi_blocks;
+       unsigned int dqi_free_blk;
+       unsigned int dqi_free_entry;
++      unsigned int dqi_revision;
+ };
+ #endif /* _LINUX_DQBLK_V2_H */
+diff -rNpu linux-2.6.16.54-0.2.5/include/linux/quota.h linux-2.6.16.54-0.2.5-quota/include/linux/quota.h
+--- linux-2.6.16.54-0.2.5/include/linux/quota.h        2006-03-20 08:53:29.000000000 +0300
++++ linux-2.6.16.54-0.2.5-quota/include/linux/quota.h  2008-03-17 23:39:54.000000000 +0300
+@@ -148,12 +148,12 @@ struct if_dqinfo {
+  * Data for one user/group kept in memory
+  */
+ struct mem_dqblk {
+-      __u32 dqb_bhardlimit;   /* absolute limit on disk blks alloc */
+-      __u32 dqb_bsoftlimit;   /* preferred limit on disk blks */
++      qsize_t dqb_bhardlimit; /* absolute limit on disk blks alloc */
++      qsize_t dqb_bsoftlimit; /* preferred limit on disk blks */
+       qsize_t dqb_curspace;   /* current used space */
+-      __u32 dqb_ihardlimit;   /* absolute limit on allocated inodes */
+-      __u32 dqb_isoftlimit;   /* preferred inode limit */
+-      __u32 dqb_curinodes;    /* current # allocated inodes */
++      qsize_t dqb_ihardlimit; /* absolute limit on allocated inodes */
++      qsize_t dqb_isoftlimit; /* preferred inode limit */
++      qsize_t dqb_curinodes;  /* current # allocated inodes */
+       time_t dqb_btime;       /* time limit for excessive disk use */
+       time_t dqb_itime;       /* time limit for excessive inode use */
+ };
+@@ -169,6 +169,8 @@ struct mem_dqinfo {
+       unsigned long dqi_flags;
+       unsigned int dqi_bgrace;
+       unsigned int dqi_igrace;
++      qsize_t dqi_maxblimit;
++      qsize_t dqi_maxilimit;
+       union {
+               struct v1_mem_dqinfo v1_i;
+               struct v2_mem_dqinfo v2_i;
+diff -rNpu linux-2.6.16.54-0.2.5/include/linux/quotaio_v2.h linux-2.6.16.54-0.2.5-quota/include/linux/quotaio_v2.h
+--- linux-2.6.16.54-0.2.5/include/linux/quotaio_v2.h   2006-03-20 08:53:29.000000000 +0300
++++ linux-2.6.16.54-0.2.5-quota/include/linux/quotaio_v2.h     2008-03-17 23:39:54.000000000 +0300
+@@ -16,28 +16,51 @@
+       0xd9c01927      /* GRPQUOTA */\
+ }
+-#define V2_INITQVERSIONS {\
++#define V2_INITQVERSIONS_R0 {\
+       0,              /* USRQUOTA */\
+       0               /* GRPQUOTA */\
+ }
++#define V2_INITQVERSIONS_R1 {\
++      1,              /* USRQUOTA */\
++      1               /* GRPQUOTA */\
++}
++
+ /*
+  * The following structure defines the format of the disk quota file
+  * (as it appears on disk) - the file is a radix tree whose leaves point
+  * to blocks of these structures.
+  */
+-struct v2_disk_dqblk {
++struct v2_disk_dqblk_r0 {
+       __le32 dqb_id;          /* id this quota applies to */
+       __le32 dqb_ihardlimit;  /* absolute limit on allocated inodes */
+       __le32 dqb_isoftlimit;  /* preferred inode limit */
+       __le32 dqb_curinodes;   /* current # allocated inodes */
+-      __le32 dqb_bhardlimit;  /* absolute limit on disk space (in QUOTABLOCK_SIZE) */
+-      __le32 dqb_bsoftlimit;  /* preferred limit on disk space (in QUOTABLOCK_SIZE) */
++      __le32 dqb_bhardlimit;  /* absolute limit on disk space */
++      __le32 dqb_bsoftlimit;  /* preferred limit on disk space */
++      __le64 dqb_curspace;    /* current space occupied (in bytes) */
++      __le64 dqb_btime;       /* time limit for excessive disk use */
++      __le64 dqb_itime;       /* time limit for excessive inode use */
++};
++
++struct v2_disk_dqblk_r1 {
++      __le32 dqb_id;          /* id this quota applies to */
++      __le32 dqb_padding;     /* padding field */
++      __le64 dqb_ihardlimit;  /* absolute limit on allocated inodes */
++      __le64 dqb_isoftlimit;  /* preferred inode limit */
++      __le64 dqb_curinodes;   /* current # allocated inodes */
++      __le64 dqb_bhardlimit;  /* absolute limit on disk space */
++      __le64 dqb_bsoftlimit;  /* preferred limit on disk space */
+       __le64 dqb_curspace;    /* current space occupied (in bytes) */
+       __le64 dqb_btime;       /* time limit for excessive disk use */
+       __le64 dqb_itime;       /* time limit for excessive inode use */
+ };
++union v2_disk_dqblk {
++      struct v2_disk_dqblk_r0 r0;
++      struct v2_disk_dqblk_r1 r1;
++};
++
+ /*
+  * Here are header structures as written on disk and their in-memory copies
+  */
+@@ -59,7 +82,7 @@ struct v2_disk_dqinfo {
+ /*
+  *  Structure of header of block with quota structures. It is padded to 16 bytes so
+- *  there will be space for exactly 21 quota-entries in a block
++ *  there will be space for exactly 21 (r0) or 14 (r1) quota-entries in a block
+  */
+ struct v2_disk_dqdbheader {
+       __le32 dqdh_next_free;  /* Number of next block with free entry */
+@@ -74,6 +97,5 @@ struct v2_disk_dqdbheader {
+ #define V2_DQBLKSIZE  (1 << V2_DQBLKSIZE_BITS)        /* Size of block with quota structures */
+ #define V2_DQTREEOFF  1               /* Offset of tree in file in blocks */
+ #define V2_DQTREEDEPTH        4               /* Depth of quota tree */
+-#define V2_DQSTRINBLK ((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk))     /* Number of entries in one blocks */
+ #endif /* _LINUX_QUOTAIO_V2_H */
diff --git a/lustre/kernel_patches/patches/quota-large-limits-sles10.patch b/lustre/kernel_patches/patches/quota-large-limits-sles10.patch
new file mode 100644 (file)
index 0000000..fcef1c2
--- /dev/null
@@ -0,0 +1,616 @@
+diff -rNpu linux-2.6.16.54-0.2.5/fs/dquot.c linux-2.6.16.54-0.2.5-quota/fs/dquot.c
+--- linux-2.6.16.54-0.2.5/fs/dquot.c   2008-03-18 15:48:26.000000000 +0300
++++ linux-2.6.16.54-0.2.5-quota/fs/dquot.c     2008-03-17 22:43:11.000000000 +0300
+@@ -1588,10 +1588,19 @@ int vfs_get_dqblk(struct super_block *sb
+ }
+ /* Generic routine for setting common part of quota structure */
+-static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
++static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
+ {
+       struct mem_dqblk *dm = &dquot->dq_dqb;
+       int check_blim = 0, check_ilim = 0;
++      struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
++
++      if ((di->dqb_valid & QIF_BLIMITS &&
++           (di->dqb_bhardlimit > dqi->dqi_maxblimit ||
++            di->dqb_bsoftlimit > dqi->dqi_maxblimit)) ||
++          (di->dqb_valid & QIF_ILIMITS &&
++           (di->dqb_ihardlimit > dqi->dqi_maxilimit ||
++            di->dqb_isoftlimit > dqi->dqi_maxilimit)))
++              return -ERANGE;
+       spin_lock(&dq_data_lock);
+       if (di->dqb_valid & QIF_SPACE) {
+@@ -1623,7 +1632,7 @@ static void do_set_dqblk(struct dquot *d
+                       clear_bit(DQ_BLKS_B, &dquot->dq_flags);
+               }
+               else if (!(di->dqb_valid & QIF_BTIME))  /* Set grace only if user hasn't provided his own... */
+-                      dm->dqb_btime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace;
++                      dm->dqb_btime = get_seconds() + dqi->dqi_bgrace;
+       }
+       if (check_ilim) {
+               if (!dm->dqb_isoftlimit || dm->dqb_curinodes < dm->dqb_isoftlimit) {
+@@ -1631,7 +1640,7 @@ static void do_set_dqblk(struct dquot *d
+                       clear_bit(DQ_INODES_B, &dquot->dq_flags);
+               }
+               else if (!(di->dqb_valid & QIF_ITIME))  /* Set grace only if user hasn't provided his own... */
+-                      dm->dqb_itime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
++                      dm->dqb_itime = get_seconds() + dqi->dqi_igrace;
+       }
+       if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || dm->dqb_isoftlimit)
+               clear_bit(DQ_FAKE_B, &dquot->dq_flags);
+@@ -1639,21 +1648,24 @@ static void do_set_dqblk(struct dquot *d
+               set_bit(DQ_FAKE_B, &dquot->dq_flags);
+       spin_unlock(&dq_data_lock);
+       mark_dquot_dirty(dquot);
++
++      return 0;
+ }
+ int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di)
+ {
+       struct dquot *dquot;
++      int rc;
+       down(&sb_dqopt(sb)->dqonoff_sem);
+       if (!(dquot = dqget(sb, id, type))) {
+               up(&sb_dqopt(sb)->dqonoff_sem);
+               return -ESRCH;
+       }
+-      do_set_dqblk(dquot, di);
++      rc = do_set_dqblk(dquot, di);
+       dqput(dquot);
+       up(&sb_dqopt(sb)->dqonoff_sem);
+-      return 0;
++      return rc;
+ }
+ /* Generic routine for getting common part of quota file information */
+diff -rNpu linux-2.6.16.54-0.2.5/fs/quota_v1.c linux-2.6.16.54-0.2.5-quota/fs/quota_v1.c
+--- linux-2.6.16.54-0.2.5/fs/quota_v1.c        2006-03-20 08:53:29.000000000 +0300
++++ linux-2.6.16.54-0.2.5-quota/fs/quota_v1.c  2008-03-17 22:42:47.000000000 +0300
+@@ -139,6 +139,9 @@ static int v1_read_file_info(struct supe
+               goto out;
+       }
+       ret = 0;
++      /* limits are stored as unsigned 32-bit data */
++      dqopt->info[type].dqi_maxblimit = 0xffffffff;
++      dqopt->info[type].dqi_maxilimit = 0xffffffff;
+       dqopt->info[type].dqi_igrace = dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME;
+       dqopt->info[type].dqi_bgrace = dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME;
+ out:
+diff -rNpu linux-2.6.16.54-0.2.5/fs/quota_v2.c linux-2.6.16.54-0.2.5-quota/fs/quota_v2.c
+--- linux-2.6.16.54-0.2.5/fs/quota_v2.c        2006-03-20 08:53:29.000000000 +0300
++++ linux-2.6.16.54-0.2.5-quota/fs/quota_v2.c  2008-03-18 11:58:02.000000000 +0300
+@@ -23,26 +23,64 @@ MODULE_LICENSE("GPL");
+ typedef char *dqbuf_t;
+ #define GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff)
+-#define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader)))
++#define GETENTRIES(buf) ((union v2_disk_dqblk *)(((char *)buf) + \
++                       sizeof(struct v2_disk_dqdbheader)))
++#define REV_ASSERT(r) BUG_ON((rev) != 0 && (rev) != 1)
++
++static const union v2_disk_dqblk emptydquot;
++static const union v2_disk_dqblk fakedquot[2] = {
++      {.r0 = {.dqb_itime = __constant_cpu_to_le64(1LLU)} },
++      {.r1 = {.dqb_itime = __constant_cpu_to_le64(1LLU)} }
++};
+-/* Check whether given file is really vfsv0 quotafile */
+-static int v2_check_quota_file(struct super_block *sb, int type)
++static inline uint v2_dqblksz(uint rev)
++{
++      uint sz;
++
++      REV_ASSERT(rev);
++
++      if (rev == 0)
++              sz = sizeof(struct v2_disk_dqblk_r0);
++      else
++              sz = sizeof(struct v2_disk_dqblk_r1);
++
++      return sz;
++}
++
++/* Number of quota entries in a block */
++static inline int v2_dqstrinblk(uint rev)
++{
++      return (V2_DQBLKSIZE-sizeof(struct v2_disk_dqdbheader))/v2_dqblksz(rev);
++}
++
++/* Get revision of a quota file, -1 if it does not look a quota file */
++static int v2_quota_file_revision(struct super_block *sb, int type)
+ {
+       struct v2_disk_dqheader dqhead;
+       ssize_t size;
+       static const uint quota_magics[] = V2_INITQMAGICS;
+-      static const uint quota_versions[] = V2_INITQVERSIONS;
++      static const uint quota_versions_r0[] = V2_INITQVERSIONS_R0;
++      static const uint quota_versions_r1[] = V2_INITQVERSIONS_R1;
+  
+       size = sb->s_op->quota_read(sb, type, (char *)&dqhead, sizeof(struct v2_disk_dqheader), 0);
+       if (size != sizeof(struct v2_disk_dqheader)) {
+               printk("quota_v2: failed read expected=%zd got=%zd\n",
+                       sizeof(struct v2_disk_dqheader), size);
+-              return 0;
++              return -1;
+       }
+-      if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
+-          le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
+-              return 0;
+-      return 1;
++      if (le32_to_cpu(dqhead.dqh_magic) == quota_magics[type]) {
++              if (le32_to_cpu(dqhead.dqh_version) == quota_versions_r0[type])
++                      return 0;
++              if (le32_to_cpu(dqhead.dqh_version) == quota_versions_r1[type])
++                      return 1;
++      }
++      return -1;
++}
++
++/* Check whether given file is really vfsv0 quotafile */
++static inline int v2_check_quota_file(struct super_block *sb, int type)
++{
++      return v2_quota_file_revision(sb, type) != -1;
+ }
+ /* Read information header from quota file */
+@@ -51,6 +89,13 @@ static int v2_read_file_info(struct supe
+       struct v2_disk_dqinfo dinfo;
+       struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
+       ssize_t size;
++      int rev;
++
++      rev = v2_quota_file_revision(sb, type);
++      if (rev < 0) {
++              printk(KERN_WARNING "Second quota file check failed.\n");
++              return -1;
++      }
+       size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
+              sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
+@@ -65,6 +110,16 @@ static int v2_read_file_info(struct supe
+       info->u.v2_i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
+       info->u.v2_i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
+       info->u.v2_i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
++
++      info->u.v2_i.dqi_revision = rev;
++      if (rev == 0) {
++              info->dqi_maxblimit = 0xffffffffULL;
++              info->dqi_maxilimit = 0xffffffffULL;
++      } else {
++              info->dqi_maxblimit = 0xffffffffffffffffULL;
++              info->dqi_maxilimit = 0xffffffffffffffffULL;
++      }
++
+       return 0;
+ }
+@@ -94,29 +149,61 @@ static int v2_write_file_info(struct sup
+       return 0;
+ }
+-static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d)
++static void disk2memdqb(struct mem_dqblk *m, union v2_disk_dqblk *d, uint rev)
+ {
+-      m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
+-      m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
+-      m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
+-      m->dqb_itime = le64_to_cpu(d->dqb_itime);
+-      m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit);
+-      m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit);
+-      m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
+-      m->dqb_btime = le64_to_cpu(d->dqb_btime);
+-}
+-
+-static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
+-{
+-      d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
+-      d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
+-      d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
+-      d->dqb_itime = cpu_to_le64(m->dqb_itime);
+-      d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit);
+-      d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit);
+-      d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
+-      d->dqb_btime = cpu_to_le64(m->dqb_btime);
+-      d->dqb_id = cpu_to_le32(id);
++      REV_ASSERT(rev);
++
++      if (rev == 0) {
++              struct v2_disk_dqblk_r0 *ddqblk = &d->r0;
++              m->dqb_ihardlimit = le32_to_cpu(ddqblk->dqb_ihardlimit);
++              m->dqb_isoftlimit = le32_to_cpu(ddqblk->dqb_isoftlimit);
++              m->dqb_curinodes = le32_to_cpu(ddqblk->dqb_curinodes);
++              m->dqb_itime = le64_to_cpu(ddqblk->dqb_itime);
++              m->dqb_bhardlimit = le32_to_cpu(ddqblk->dqb_bhardlimit);
++              m->dqb_bsoftlimit = le32_to_cpu(ddqblk->dqb_bsoftlimit);
++              m->dqb_curspace = le64_to_cpu(ddqblk->dqb_curspace);
++              m->dqb_btime = le64_to_cpu(ddqblk->dqb_btime);
++      } else {
++              struct v2_disk_dqblk_r1 *ddqblk = &d->r1;
++              m->dqb_ihardlimit = le64_to_cpu(ddqblk->dqb_ihardlimit);
++              m->dqb_isoftlimit = le64_to_cpu(ddqblk->dqb_isoftlimit);
++              m->dqb_curinodes = le64_to_cpu(ddqblk->dqb_curinodes);
++              m->dqb_itime = le64_to_cpu(ddqblk->dqb_itime);
++              m->dqb_bhardlimit = le64_to_cpu(ddqblk->dqb_bhardlimit);
++              m->dqb_bsoftlimit = le64_to_cpu(ddqblk->dqb_bsoftlimit);
++              m->dqb_curspace = le64_to_cpu(ddqblk->dqb_curspace);
++              m->dqb_btime = le64_to_cpu(ddqblk->dqb_btime);
++      }
++}
++
++static void mem2diskdqb(union v2_disk_dqblk *d, struct mem_dqblk *m,
++                      qid_t id, uint rev)
++{
++      REV_ASSERT(rev);
++
++      if (rev == 0) {
++              struct v2_disk_dqblk_r0 *ddqblk = &d->r0;
++              ddqblk->dqb_id = cpu_to_le32(id);
++              ddqblk->dqb_ihardlimit = cpu_to_le32((__u32)m->dqb_ihardlimit);
++              ddqblk->dqb_isoftlimit = cpu_to_le32((__u32)m->dqb_isoftlimit);
++              ddqblk->dqb_curinodes = cpu_to_le32((__u32)m->dqb_curinodes);
++              ddqblk->dqb_itime = cpu_to_le64(m->dqb_itime);
++              ddqblk->dqb_bhardlimit = cpu_to_le32((__u32)m->dqb_bhardlimit);
++              ddqblk->dqb_bsoftlimit = cpu_to_le32((__u32)m->dqb_bsoftlimit);
++              ddqblk->dqb_curspace = cpu_to_le64(m->dqb_curspace);
++              ddqblk->dqb_btime = cpu_to_le64(ddqblk->dqb_btime);
++      } else {
++              struct v2_disk_dqblk_r1 *ddqblk = &d->r1;
++              ddqblk->dqb_id = cpu_to_le32(id);
++              ddqblk->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
++              ddqblk->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
++              ddqblk->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
++              ddqblk->dqb_itime = cpu_to_le64(m->dqb_itime);
++              ddqblk->dqb_bhardlimit = cpu_to_le64(m->dqb_bhardlimit);
++              ddqblk->dqb_bsoftlimit = cpu_to_le64(m->dqb_bsoftlimit);
++              ddqblk->dqb_curspace = cpu_to_le64(m->dqb_curspace);
++              ddqblk->dqb_btime = cpu_to_le64(ddqblk->dqb_btime);
++      }
+ }
+ static dqbuf_t getdqbuf(void)
+@@ -268,10 +355,10 @@ static uint find_free_dqentry(struct dqu
+ {
+       struct super_block *sb = dquot->dq_sb;
+       struct mem_dqinfo *info = sb_dqopt(sb)->info+dquot->dq_type;
+-      uint blk, i;
++      uint blk, i, rev = info->u.v2_i.dqi_revision;
++      uint dqblksz = v2_dqblksz(rev), dqstrinblk = v2_dqstrinblk(rev);
+       struct v2_disk_dqdbheader *dh;
+-      struct v2_disk_dqblk *ddquot;
+-      struct v2_disk_dqblk fakedquot;
++      union v2_disk_dqblk *ddquot;
+       dqbuf_t buf;
+       *err = 0;
+@@ -298,17 +385,18 @@ static uint find_free_dqentry(struct dqu
+               info->u.v2_i.dqi_free_entry = blk;
+               mark_info_dirty(sb, dquot->dq_type);
+       }
+-      if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK)   /* Block will be full? */
++      /* Block will be full? */
++      if (le16_to_cpu(dh->dqdh_entries)+1 >= dqstrinblk)
+               if ((*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) {
+                       printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
+                       goto out_buf;
+               }
+       dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)+1);
+-      memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
+       /* Find free structure in block */
+-      for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++);
++      for (i = 0; i < dqstrinblk && memcmp(&emptydquot, ddquot, dqblksz);
++           i++, ddquot = (char *)ddquot + dqblksz);
+ #ifdef __QUOTA_V2_PARANOIA
+-      if (i == V2_DQSTRINBLK) {
++      if (i == dqstrinblk) {
+               printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
+               *err = -EIO;
+               goto out_buf;
+@@ -318,7 +406,8 @@ static uint find_free_dqentry(struct dqu
+               printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
+               goto out_buf;
+       }
+-      dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+sizeof(struct v2_disk_dqdbheader)+i*sizeof(struct v2_disk_dqblk);
++      dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+
++                      ((char *)ddquot - (char *)buf);
+       freedqbuf(buf);
+       return blk;
+ out_buf:
+@@ -392,7 +481,9 @@ static int v2_write_dquot(struct dquot *
+ {
+       int type = dquot->dq_type;
+       ssize_t ret;
+-      struct v2_disk_dqblk ddquot, empty;
++      union v2_disk_dqblk ddquot;
++      uint rev = sb_dqopt(dquot->dq_sb)->info[type].u.v2_i.dqi_revision;
++      uint dqblksz = v2_dqblksz(rev);
+       /* dq_off is guarded by dqio_sem */
+       if (!dquot->dq_off)
+@@ -401,18 +492,22 @@ static int v2_write_dquot(struct dquot *
+                       return ret;
+               }
+       spin_lock(&dq_data_lock);
+-      mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
++      mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id, rev);
+       /* Argh... We may need to write structure full of zeroes but that would be
+        * treated as an empty place by the rest of the code. Format change would
+        * be definitely cleaner but the problems probably are not worth it */
+-      memset(&empty, 0, sizeof(struct v2_disk_dqblk));
+-      if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
+-              ddquot.dqb_itime = cpu_to_le64(1);
++      if (!memcmp(&emptydquot, &ddquot, dqblksz)) {
++              if (rev == 0)
++                      ddquot.r0.dqb_itime = cpu_to_le64(1);
++              else
++                      ddquot.r1.dqb_itime = cpu_to_le64(1);
++      }
+       spin_unlock(&dq_data_lock);
+       ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
+-            (char *)&ddquot, sizeof(struct v2_disk_dqblk), dquot->dq_off);
+-      if (ret != sizeof(struct v2_disk_dqblk)) {
+-              printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id);
++            (char *)&ddquot, dqblksz, dquot->dq_off);
++      if (ret != dqblksz) {
++              printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
++                      dquot->dq_sb->s_id);
+               if (ret >= 0)
+                       ret = -ENOSPC;
+       }
+@@ -431,6 +526,7 @@ static int free_dqentry(struct dquot *dq
+       struct v2_disk_dqdbheader *dh;
+       dqbuf_t buf = getdqbuf();
+       int ret = 0;
++      uint rev = sb_dqopt(sb)->info[type].u.v2_i.dqi_revision;
+       if (!buf)
+               return -ENOMEM;
+@@ -456,8 +552,8 @@ static int free_dqentry(struct dquot *dq
+       }
+       else {
+               memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0,
+-                sizeof(struct v2_disk_dqblk));
+-              if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
++                v2_dqblksz(rev));
++              if (le16_to_cpu(dh->dqdh_entries) == v2_dqstrinblk(rev)-1) {
+                       /* Insert will write block itself */
+                       if ((ret = insert_free_dqentry(sb, type, buf, blk)) < 0) {
+                               printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
+@@ -529,41 +625,56 @@ static int v2_delete_dquot(struct dquot 
+       return remove_tree(dquot, &tmp, 0);
+ }
++static inline __u32 dqid(union v2_disk_dqblk *ddquot, uint rev)
++{
++      __u32 dq_id;
++
++      REV_ASSERT(rev);
++
++      if (rev == 0)
++              dq_id = le32_to_cpu(ddquot->r0.dqb_id);
++      else
++              dq_id = le32_to_cpu(ddquot->r1.dqb_id);
++
++      return dq_id;
++}
++
+ /* Find entry in block */
+ static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
+ {
+       dqbuf_t buf = getdqbuf();
+       loff_t ret = 0;
+       int i;
+-      struct v2_disk_dqblk *ddquot = GETENTRIES(buf);
++      union v2_disk_dqblk *ddquot = GETENTRIES(buf);
++      int type = dquot->dq_type;
++      uint rev = sb_dqopt(dquot->dq_sb)->info[type].u.v2_i.dqi_revision;
++      uint dqblksz = v2_dqblksz(rev), dqstrinblk = v2_dqstrinblk(rev);
+       if (!buf)
+               return -ENOMEM;
+-      if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
++
++      ret = read_blk(dquot->dq_sb, type, blk, buf);
++      if (ret < 0) {
+               printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
+               goto out_buf;
+       }
+       if (dquot->dq_id)
+-              for (i = 0; i < V2_DQSTRINBLK &&
+-                   le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
++              for (i = 0; i < dqstrinblk && dqid(ddquot, rev) != dquot->dq_id;
++                   i++, ddquot = (char *)ddquot + dqblksz);
+       else {  /* ID 0 as a bit more complicated searching... */
+-              struct v2_disk_dqblk fakedquot;
+-
+-              memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
+-              for (i = 0; i < V2_DQSTRINBLK; i++)
+-                      if (!le32_to_cpu(ddquot[i].dqb_id) &&
+-                          memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
++              for (i = 0; i < dqstrinblk; i++, ddquot = (char *)ddquot+dqblksz)
++                      if (!dqid(ddquot, rev) &&
++                          memcmp(&emptydquot, ddquot, dqblksz))
+                               break;
+       }
+-      if (i == V2_DQSTRINBLK) {
++      if (i == dqstrinblk) {
+               printk(KERN_ERR "VFS: Quota for id %u referenced "
+                 "but not present.\n", dquot->dq_id);
+               ret = -EIO;
+               goto out_buf;
+       }
+       else
+-              ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct
+-                v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
++              ret = (blk << V2_DQBLKSIZE_BITS)+((char *)ddquot-(char *)buf);
+ out_buf:
+       freedqbuf(buf);
+       return ret;
+@@ -605,7 +716,7 @@ static int v2_read_dquot(struct dquot *d
+ {
+       int type = dquot->dq_type;
+       loff_t offset;
+-      struct v2_disk_dqblk ddquot, empty;
++      union v2_disk_dqblk ddquot;
+       int ret = 0;
+ #ifdef __QUOTA_V2_PARANOIA
+@@ -626,25 +737,30 @@ static int v2_read_dquot(struct dquot *d
+               ret = offset;
+       }
+       else {
++              uint rev = sb_dqopt(dquot->dq_sb)->info[type].u.v2_i.
++                         dqi_revision;
++              uint  dqblksz = v2_dqblksz(rev);
+               dquot->dq_off = offset;
+-              if ((ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
+-                  (char *)&ddquot, sizeof(struct v2_disk_dqblk), offset))
+-                  != sizeof(struct v2_disk_dqblk)) {
++              ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
++                                         (char *)&ddquot, dqblksz, offset);
++              if (ret != dqblksz) {
+                       if (ret >= 0)
+                               ret = -EIO;
+                       printk(KERN_ERR "VFS: Error while reading quota "
+                         "structure for id %u.\n", dquot->dq_id);
+-                      memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
++                      memset(&ddquot, 0, dqblksz);
+               }
+               else {
+                       ret = 0;
+                       /* We need to escape back all-zero structure */
+-                      memset(&empty, 0, sizeof(struct v2_disk_dqblk));
+-                      empty.dqb_itime = cpu_to_le64(1);
+-                      if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
+-                              ddquot.dqb_itime = 0;
++                      if (!memcmp(&fakedquot[rev], &ddquot, dqblksz)) {
++                              if (rev == 0)
++                                      ddquot.r0.dqb_itime = cpu_to_le64(0);
++                              else
++                                      ddquot.r1.dqb_itime = cpu_to_le64(0);
++                      }
+               }
+-              disk2memdqb(&dquot->dq_dqb, &ddquot);
++              disk2memdqb(&dquot->dq_dqb, &ddquot, rev);
+               if (!dquot->dq_dqb.dqb_bhardlimit &&
+                       !dquot->dq_dqb.dqb_bsoftlimit &&
+                       !dquot->dq_dqb.dqb_ihardlimit &&
+diff -rNpu linux-2.6.16.54-0.2.5/include/linux/dqblk_v2.h linux-2.6.16.54-0.2.5-quota/include/linux/dqblk_v2.h
+--- linux-2.6.16.54-0.2.5/include/linux/dqblk_v2.h     2006-03-20 08:53:29.000000000 +0300
++++ linux-2.6.16.54-0.2.5-quota/include/linux/dqblk_v2.h       2008-03-17 23:39:54.000000000 +0300
+@@ -21,6 +21,7 @@ struct v2_mem_dqinfo {
+       unsigned int dqi_blocks;
+       unsigned int dqi_free_blk;
+       unsigned int dqi_free_entry;
++      unsigned int dqi_revision;
+ };
+ #endif /* _LINUX_DQBLK_V2_H */
+diff -rNpu linux-2.6.16.54-0.2.5/include/linux/quota.h linux-2.6.16.54-0.2.5-quota/include/linux/quota.h
+--- linux-2.6.16.54-0.2.5/include/linux/quota.h        2006-03-20 08:53:29.000000000 +0300
++++ linux-2.6.16.54-0.2.5-quota/include/linux/quota.h  2008-03-17 23:39:54.000000000 +0300
+@@ -148,12 +148,12 @@ struct if_dqinfo {
+  * Data for one user/group kept in memory
+  */
+ struct mem_dqblk {
+-      __u32 dqb_bhardlimit;   /* absolute limit on disk blks alloc */
+-      __u32 dqb_bsoftlimit;   /* preferred limit on disk blks */
++      qsize_t dqb_bhardlimit; /* absolute limit on disk blks alloc */
++      qsize_t dqb_bsoftlimit; /* preferred limit on disk blks */
+       qsize_t dqb_curspace;   /* current used space */
+-      __u32 dqb_ihardlimit;   /* absolute limit on allocated inodes */
+-      __u32 dqb_isoftlimit;   /* preferred inode limit */
+-      __u32 dqb_curinodes;    /* current # allocated inodes */
++      qsize_t dqb_ihardlimit; /* absolute limit on allocated inodes */
++      qsize_t dqb_isoftlimit; /* preferred inode limit */
++      qsize_t dqb_curinodes;  /* current # allocated inodes */
+       time_t dqb_btime;       /* time limit for excessive disk use */
+       time_t dqb_itime;       /* time limit for excessive inode use */
+ };
+@@ -169,6 +169,8 @@ struct mem_dqinfo {
+       unsigned long dqi_flags;
+       unsigned int dqi_bgrace;
+       unsigned int dqi_igrace;
++      qsize_t dqi_maxblimit;
++      qsize_t dqi_maxilimit;
+       union {
+               struct v1_mem_dqinfo v1_i;
+               struct v2_mem_dqinfo v2_i;
+diff -rNpu linux-2.6.16.54-0.2.5/include/linux/quotaio_v2.h linux-2.6.16.54-0.2.5-quota/include/linux/quotaio_v2.h
+--- linux-2.6.16.54-0.2.5/include/linux/quotaio_v2.h   2006-03-20 08:53:29.000000000 +0300
++++ linux-2.6.16.54-0.2.5-quota/include/linux/quotaio_v2.h     2008-03-17 23:39:54.000000000 +0300
+@@ -16,28 +16,51 @@
+       0xd9c01927      /* GRPQUOTA */\
+ }
+-#define V2_INITQVERSIONS {\
++#define V2_INITQVERSIONS_R0 {\
+       0,              /* USRQUOTA */\
+       0               /* GRPQUOTA */\
+ }
++#define V2_INITQVERSIONS_R1 {\
++      1,              /* USRQUOTA */\
++      1               /* GRPQUOTA */\
++}
++
+ /*
+  * The following structure defines the format of the disk quota file
+  * (as it appears on disk) - the file is a radix tree whose leaves point
+  * to blocks of these structures.
+  */
+-struct v2_disk_dqblk {
++struct v2_disk_dqblk_r0 {
+       __le32 dqb_id;          /* id this quota applies to */
+       __le32 dqb_ihardlimit;  /* absolute limit on allocated inodes */
+       __le32 dqb_isoftlimit;  /* preferred inode limit */
+       __le32 dqb_curinodes;   /* current # allocated inodes */
+-      __le32 dqb_bhardlimit;  /* absolute limit on disk space (in QUOTABLOCK_SIZE) */
+-      __le32 dqb_bsoftlimit;  /* preferred limit on disk space (in QUOTABLOCK_SIZE) */
++      __le32 dqb_bhardlimit;  /* absolute limit on disk space */
++      __le32 dqb_bsoftlimit;  /* preferred limit on disk space */
++      __le64 dqb_curspace;    /* current space occupied (in bytes) */
++      __le64 dqb_btime;       /* time limit for excessive disk use */
++      __le64 dqb_itime;       /* time limit for excessive inode use */
++};
++
++struct v2_disk_dqblk_r1 {
++      __le32 dqb_id;          /* id this quota applies to */
++      __le32 dqb_padding;     /* padding field */
++      __le64 dqb_ihardlimit;  /* absolute limit on allocated inodes */
++      __le64 dqb_isoftlimit;  /* preferred inode limit */
++      __le64 dqb_curinodes;   /* current # allocated inodes */
++      __le64 dqb_bhardlimit;  /* absolute limit on disk space */
++      __le64 dqb_bsoftlimit;  /* preferred limit on disk space */
+       __le64 dqb_curspace;    /* current space occupied (in bytes) */
+       __le64 dqb_btime;       /* time limit for excessive disk use */
+       __le64 dqb_itime;       /* time limit for excessive inode use */
+ };
++union v2_disk_dqblk {
++      struct v2_disk_dqblk_r0 r0;
++      struct v2_disk_dqblk_r1 r1;
++};
++
+ /*
+  * Here are header structures as written on disk and their in-memory copies
+  */
+@@ -59,7 +82,7 @@ struct v2_disk_dqinfo {
+ /*
+  *  Structure of header of block with quota structures. It is padded to 16 bytes so
+- *  there will be space for exactly 21 quota-entries in a block
++ *  there will be space for exactly 21 (r0) or 14 (r1) quota-entries in a block
+  */
+ struct v2_disk_dqdbheader {
+       __le32 dqdh_next_free;  /* Number of next block with free entry */
+@@ -74,6 +97,5 @@ struct v2_disk_dqdbheader {
+ #define V2_DQBLKSIZE  (1 << V2_DQBLKSIZE_BITS)        /* Size of block with quota structures */
+ #define V2_DQTREEOFF  1               /* Offset of tree in file in blocks */
+ #define V2_DQTREEDEPTH        4               /* Depth of quota tree */
+-#define V2_DQSTRINBLK ((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk))     /* Number of entries in one blocks */
+ #endif /* _LINUX_QUOTAIO_V2_H */
index 9e7a8ed..8495289 100644 (file)
@@ -19,3 +19,4 @@ raid5-merge-ios-rhel5.patch
 raid5-zerocopy-rhel5.patch
 md-rebuild-policy.patch
 jbd-journal-chksum-2.6.18-vanilla.patch
+quota-large-limits-rhel5.patch
index 72adc21..070f943 100644 (file)
@@ -10,7 +10,9 @@ export_symbol_numa-2.6-fc5.patch
 blkdev_tunables-2.6-sles10.patch
 jbd-stats-2.6-sles10.patch
 i_filter_data.patch
+quota-fix-oops-in-invalidate_dquots.patch
 jbd-journal-chksum-2.6-sles10.patch
 proc-sleep-2.6.16-sles10.patch 
 export-nr_free_buffer_pages.patch 
 fmode-exec-2.6-sles10.patch
+quota-large-limits-sles10.patch
index eba2991..fe32803 100644 (file)
@@ -11,3 +11,4 @@ export-2.6.18-vanilla.patch
 8kstack-2.6.12.patch
 export-show_task-2.6.18-vanilla.patch 
 sd_iostats-2.6.22-vanilla.patch
+quota-large-limits-rhel5.patch
index 81d357b..49fd0bf 100644 (file)
@@ -51,7 +51,6 @@
 #include <lustre_sec.h>
 #include "ldlm_internal.h"
 
-
 /* @priority: if non-zero, move the selected to the list head
  * @create: if zero, only search in existed connections
  */
@@ -2166,33 +2165,37 @@ void target_committed_to_req(struct ptlrpc_request *req)
 
 EXPORT_SYMBOL(target_committed_to_req);
 
-#ifdef HAVE_QUOTA_SUPPORT
 int target_handle_qc_callback(struct ptlrpc_request *req)
 {
         struct obd_quotactl *oqctl;
         struct client_obd *cli = &req->rq_export->exp_obd->u.cli;
 
         oqctl = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
-        if (oqctl == NULL)
+        if (oqctl == NULL) {
+                CERROR("Can't unpack obd_quotactl\n");
                 RETURN(-EPROTO);
+        }
 
         cli->cl_qchk_stat = oqctl->qc_stat;
 
         return 0;
 }
 
+#ifdef HAVE_QUOTA_SUPPORT
 int target_handle_dqacq_callback(struct ptlrpc_request *req)
 {
 #ifdef __KERNEL__
         struct obd_device *obd = req->rq_export->exp_obd;
         struct obd_device *master_obd;
+        struct obd_device_target *obt;
         struct lustre_quota_ctxt *qctxt;
-        struct qunit_data *qdata;
-        void* rep;
-        struct qunit_data_old *qdata_old;
+        struct qunit_data *qdata = NULL;
         int rc = 0;
         ENTRY;
 
+        if (OBD_FAIL_CHECK(OBD_FAIL_MDS_DROP_QUOTA_REQ))
+                RETURN(rc);
+
         rc = req_capsule_server_pack(&req->rq_pill);
         if (rc) {
                 CERROR("packing reply failed!: rc = %d\n", rc);
@@ -2201,52 +2204,73 @@ int target_handle_dqacq_callback(struct ptlrpc_request *req)
 
         LASSERT(req->rq_export);
 
-        /* fixed for bug10707 */
-        if ((req->rq_export->exp_connect_flags & OBD_CONNECT_QUOTA64) &&
-            !OBD_FAIL_CHECK(OBD_FAIL_QUOTA_QD_COUNT_32BIT)) {
-                CDEBUG(D_QUOTA, "qd_count is 64bit!\n");
-                rep = req_capsule_server_get(&req->rq_pill,
-                                             &RMF_QUNIT_DATA);
-                LASSERT(rep);
-                qdata = req_capsule_client_swab_get(&req->rq_pill,
-                                                    &RMF_QUNIT_DATA,
-                                          (void*)lustre_swab_qdata);
-        } else {
-                CDEBUG(D_QUOTA, "qd_count is 32bit!\n");
-                rep = req_capsule_server_get(&req->rq_pill, &RMF_QUNIT_DATA);
-                LASSERT(rep);
-                qdata_old = req_capsule_client_swab_get(&req->rq_pill,
-                                                        &RMF_QUNIT_DATA,
-                                           (void*)lustre_swab_qdata_old);
-                qdata = lustre_quota_old_to_new(qdata_old);
+        OBD_ALLOC(qdata, sizeof(struct qunit_data));
+        if (!qdata)
+                RETURN(-ENOMEM);
+        rc = quota_get_qdata(req, qdata, QUOTA_REQUEST, QUOTA_EXPORT);
+        if (rc < 0) {
+                CDEBUG(D_ERROR, "Can't unpack qunit_data(rc: %d)\n", rc);
+                GOTO(out, rc);
         }
 
-        if (qdata == NULL)
-                RETURN(-EPROTO);
-
         /* we use the observer */
-        LASSERT(obd->obd_observer && obd->obd_observer->obd_observer);
+        if (!obd->obd_observer || !obd->obd_observer->obd_observer) {
+                CERROR("Can't find the observer, it is recovering\n");
+                req->rq_status = -EIO;
+                GOTO(send_reply, rc = -EIO);
+        }
+
         master_obd = obd->obd_observer->obd_observer;
-        qctxt = &master_obd->u.obt.obt_qctxt;
+        obt = &master_obd->u.obt;
+        qctxt = &obt->obt_qctxt;
+
+        if (!qctxt->lqc_setup || !qctxt->lqc_valid) {
+                /* quota_type has not been processed yet, return EAGAIN
+                 * until we know whether or not quotas are supposed to
+                 * be enabled */
+                CDEBUG(D_QUOTA, "quota_type not processed yet, return "
+                       "-EAGAIN\n");
+                req->rq_status = -EAGAIN;
+                rc = ptlrpc_reply(req);
+                GOTO(out, rc);
+        }
+
+        down_read(&obt->obt_rwsem);
+        if (qctxt->lqc_lqs_hash == NULL) {
+                up_read(&obt->obt_rwsem);
+                /* quota_type has not been processed yet, return EAGAIN
+                 * until we know whether or not quotas are supposed to
+                 * be enabled */
+                CDEBUG(D_QUOTA, "quota_ctxt is not ready yet, return "
+                       "-EAGAIN\n");
+                req->rq_status = -EAGAIN;
+                rc = ptlrpc_reply(req);
+                GOTO(out, rc);
+        }
 
         LASSERT(qctxt->lqc_handler);
         rc = qctxt->lqc_handler(master_obd, qdata,
                                 lustre_msg_get_opc(req->rq_reqmsg));
+        up_read(&obt->obt_rwsem);
         if (rc && rc != -EDQUOT)
                 CDEBUG(rc == -EBUSY  ? D_QUOTA : D_ERROR,
                        "dqacq failed! (rc:%d)\n", rc);
+        req->rq_status = rc;
 
-        /* the qd_count might be changed in lqc_handler */
-        if ((req->rq_export->exp_connect_flags & OBD_CONNECT_QUOTA64) &&
-            !OBD_FAIL_CHECK(OBD_FAIL_QUOTA_QD_COUNT_32BIT)) {
-                memcpy(rep, qdata, sizeof(*qdata));
-        } else {
-                qdata_old = lustre_quota_new_to_old(qdata);
-                memcpy(rep, qdata_old, sizeof(*qdata_old));
+        /* there are three forms of qunit(historic causes), so we need to
+         * adjust the same form to different forms slaves needed */
+        rc = quota_copy_qdata(req, qdata, QUOTA_REPLY, QUOTA_EXPORT);
+        if (rc < 0) {
+                CDEBUG(D_ERROR, "Can't pack qunit_data(rc: %d)\n", rc);
+                GOTO(out, rc);
         }
-        req->rq_status = rc;
-        rc = ptlrpc_reply(req);
 
+        /* Block the quota req. b=14840 */
+        OBD_FAIL_TIMEOUT(OBD_FAIL_MDS_BLOCK_QUOTA_REQ, obd_timeout);
+send_reply:
+        rc = ptlrpc_reply(req);
+out:
+        OBD_FREE(qdata, sizeof(struct qunit_data));
         RETURN(rc);
 #else
         return 0;
index 27fa1af..50d4504 100644 (file)
@@ -268,7 +268,8 @@ int ldlm_lock_destroy_internal(struct ldlm_lock *lock)
         }
         lock->l_destroyed = 1;
 
-        if (lock->l_export && lock->l_export->exp_lock_hash)
+        if (lock->l_export && lock->l_export->exp_lock_hash &&
+            !hlist_unhashed(&lock->l_exp_hash))
                 lustre_hash_del(lock->l_export->exp_lock_hash,
                                 &lock->l_remote_handle, &lock->l_exp_hash);
 
index 35f3bcf..b809cba 100644 (file)
@@ -1882,7 +1882,8 @@ void ldlm_revoke_lock_cb(void *obj, void *data)
         LASSERT(!lock->l_blocking_lock);
 
         lock->l_flags |= LDLM_FL_AST_SENT;
-        if (lock->l_export && lock->l_export->exp_lock_hash)
+        if (lock->l_export && lock->l_export->exp_lock_hash &&
+            !hlist_unhashed(&lock->l_exp_hash))
                 lustre_hash_del(lock->l_export->exp_lock_hash,
                                 &lock->l_remote_handle, &lock->l_exp_hash);
         list_add_tail(&lock->l_rk_ast, rpc_list);
index 116d0c9..326a8c0 100644 (file)
@@ -22,7 +22,7 @@ LUSTRE_LIBS = libllite.a \
               $(top_builddir)/lustre/obdclass/liblustreclass.a \
               $(top_builddir)/lustre/lvfs/liblvfs.a
 
-if QUOTA
+if LIBLUSTRE
 QUOTA_LIBS = $(top_builddir)/lustre/quota/libquota.a
 endif
 
index 07b7ddd..38fb136 100644 (file)
@@ -320,7 +320,7 @@ int llu_objects_destroy(struct ptlrpc_request *req, struct inode *dir)
                 }
         }
 
-        rc = obd_destroy(llu_i2obdexp(dir), oa, lsm, &oti, NULL);
+        rc = obd_destroy(llu_i2obdexp(dir), oa, lsm, &oti, NULL, NULL);
         OBDO_FREE(oa);
         if (rc)
                 CERROR("obd destroy objid 0x"LPX64" error %d\n",
index 0de50cf..fc9bc5d 100644 (file)
@@ -77,14 +77,14 @@ void *inter_module_get(char *arg)
                 return ldlm_namespace_cleanup;
         else if (!strcmp(arg, "ldlm_replay_locks"))
                 return ldlm_replay_locks;
-#ifdef HAVE_QUOTA_SUPPORT
-        else if (!strcmp(arg, "osc_quota_interface"))
-                return &osc_quota_interface;
         else if (!strcmp(arg, "mdc_quota_interface"))
                 return &mdc_quota_interface;
+        else if (!strcmp(arg, "lmv_quota_interface"))
+                return &lmv_quota_interface;
+        else if (!strcmp(arg, "osc_quota_interface"))
+                return &osc_quota_interface;
         else if (!strcmp(arg, "lov_quota_interface"))
                 return &lov_quota_interface;
-#endif
         else
                 return NULL;
 }
index 061f82e..4366c86 100644 (file)
@@ -500,16 +500,6 @@ int ll_readdir(struct file *filp, void *cookie, filldir_t filldir)
         RETURN(rc);
 }
 
-#define QCTL_COPY(out, in)              \
-do {                                    \
-        Q_COPY(out, in, qc_cmd);        \
-        Q_COPY(out, in, qc_type);       \
-        Q_COPY(out, in, qc_id);         \
-        Q_COPY(out, in, qc_stat);       \
-        Q_COPY(out, in, qc_dqinfo);     \
-        Q_COPY(out, in, qc_dqblk);      \
-} while (0)
-
 int ll_send_mgc_param(struct obd_export *mgc, char *string)
 {
         struct mgs_send_param *msp;
@@ -1011,7 +1001,8 @@ static int ll_dir_ioctl(struct inode *inode, struct file *file,
                 struct obd_quotactl *oqctl;
                 int rc, error = 0;
 
-                if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+                if (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
+                    sbi->ll_flags & LL_SBI_RMT_CLIENT)
                         RETURN(-EPERM);
 
                 OBD_ALLOC_PTR(oqctl);
@@ -1035,7 +1026,8 @@ static int ll_dir_ioctl(struct inode *inode, struct file *file,
                 struct if_quotacheck *check;
                 int rc;
 
-                if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+                if (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
+                    sbi->ll_flags & LL_SBI_RMT_CLIENT)
                         RETURN(-EPERM);
 
                 OBD_ALLOC_PTR(check);
@@ -1063,47 +1055,39 @@ static int ll_dir_ioctl(struct inode *inode, struct file *file,
                 OBD_FREE_PTR(check);
                 RETURN(rc);
         }
-#ifdef HAVE_QUOTA_SUPPORT
         case OBD_IOC_QUOTACTL: {
                 struct if_quotactl *qctl;
-                struct obd_quotactl *oqctl;
-
-                int cmd, type, id, rc = 0;
+                int cmd, type, id, valid, rc = 0;
 
                 OBD_ALLOC_PTR(qctl);
                 if (!qctl)
                         RETURN(-ENOMEM);
 
-                OBD_ALLOC_PTR(oqctl);
-                if (!oqctl) {
-                        OBD_FREE_PTR(qctl);
-                        RETURN(-ENOMEM);
-                }
                 if (copy_from_user(qctl, (void *)arg, sizeof(*qctl)))
                         GOTO(out_quotactl, rc = -EFAULT);
 
                 cmd = qctl->qc_cmd;
                 type = qctl->qc_type;
                 id = qctl->qc_id;
+                valid = qctl->qc_valid;
+
                 switch (cmd) {
+                case LUSTRE_Q_INVALIDATE:
+                case LUSTRE_Q_FINVALIDATE:
                 case Q_QUOTAON:
                 case Q_QUOTAOFF:
                 case Q_SETQUOTA:
                 case Q_SETINFO:
-                        if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+                        if (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
+                            sbi->ll_flags & LL_SBI_RMT_CLIENT)
                                 GOTO(out_quotactl, rc = -EPERM);
                         break;
                 case Q_GETQUOTA:
                         if (((type == USRQUOTA && current->euid != id) ||
                              (type == GRPQUOTA && !in_egroup_p(id))) &&
-                            !cfs_capable(CFS_CAP_SYS_ADMIN))
+                            (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
+                             sbi->ll_flags & LL_SBI_RMT_CLIENT))
                                 GOTO(out_quotactl, rc = -EPERM);
-
-                        /* XXX: dqb_valid is borrowed as a flag to mark that
-                         *      only mds quota is wanted */
-                        if (qctl->qc_dqblk.dqb_valid)
-                                qctl->obd_uuid = sbi->ll_md_exp->exp_obd->
-                                                        u.cli.cl_target_uuid;
                         break;
                 case Q_GETINFO:
                         break;
@@ -1112,69 +1096,76 @@ static int ll_dir_ioctl(struct inode *inode, struct file *file,
                         GOTO(out_quotactl, rc = -ENOTTY);
                 }
 
-                QCTL_COPY(oqctl, qctl);
-
-                if (qctl->obd_uuid.uuid[0]) {
-                        struct obd_device *obd;
-                        struct obd_uuid *uuid = &qctl->obd_uuid;
-
-                        obd = class_find_client_notype(uuid,
-                                         &sbi->ll_dt_exp->exp_obd->obd_uuid);
-                        if (!obd)
-                                GOTO(out_quotactl, rc = -ENOENT);
+                if (valid != QC_GENERAL) {
+                        if (sbi->ll_flags & LL_SBI_RMT_CLIENT)
+                                GOTO(out_quotactl, rc = -EOPNOTSUPP);
 
                         if (cmd == Q_GETINFO)
-                                oqctl->qc_cmd = Q_GETOINFO;
+                                qctl->qc_cmd = Q_GETOINFO;
                         else if (cmd == Q_GETQUOTA)
-                                oqctl->qc_cmd = Q_GETOQUOTA;
+                                qctl->qc_cmd = Q_GETOQUOTA;
                         else
                                 GOTO(out_quotactl, rc = -EINVAL);
 
-                        if (sbi->ll_md_exp->exp_obd == obd) {
-                                rc = obd_quotactl(sbi->ll_md_exp, oqctl);
-                        } else {
-                                int i;
-                                struct obd_export *exp;
-                                struct lov_obd *lov = &sbi->ll_dt_exp->
-                                                            exp_obd->u.lov;
-
-                                for (i = 0; i < lov->desc.ld_tgt_count; i++) {
-                                        if (!lov->lov_tgts[i] ||
-                                            !lov->lov_tgts[i]->ltd_active)
-                                                continue;
-                                        exp = lov->lov_tgts[i]->ltd_exp;
-                                        if (exp->exp_obd == obd) {
-                                                rc = obd_quotactl(exp, oqctl);
-                                                break;
-                                        }
-                                }
+                        switch (valid) {
+                        case QC_MDTIDX:
+                                rc = obd_iocontrol(OBD_IOC_QUOTACTL,
+                                                   sbi->ll_md_exp,
+                                                   sizeof(*qctl), qctl, NULL);
+                                break;
+                        case QC_OSTIDX:
+                                rc = obd_iocontrol(OBD_IOC_QUOTACTL,
+                                                   sbi->ll_dt_exp,
+                                                   sizeof(*qctl), qctl, NULL);
+                                break;
+                        case QC_UUID:
+                                rc = obd_iocontrol(OBD_IOC_QUOTACTL,
+                                                   sbi->ll_md_exp,
+                                                   sizeof(*qctl), qctl, NULL);
+                                if (rc == -EAGAIN)
+                                        rc = obd_iocontrol(OBD_IOC_QUOTACTL,
+                                                           sbi->ll_dt_exp,
+                                                           sizeof(*qctl), qctl,
+                                                           NULL);
+                                break;
+                        default:
+                                rc = -EINVAL;
+                                break;
                         }
 
-                        oqctl->qc_cmd = cmd;
-                        QCTL_COPY(qctl, oqctl);
-
-                        if (copy_to_user((void *)arg, qctl, sizeof(*qctl)))
-                                rc = -EFAULT;
-
-                        GOTO(out_quotactl, rc);
-                }
-
-                rc = obd_quotactl(sbi->ll_md_exp, oqctl);
-                if (rc && rc != -EBUSY && cmd == Q_QUOTAON) {
-                        oqctl->qc_cmd = Q_QUOTAOFF;
-                        obd_quotactl(sbi->ll_md_exp, oqctl);
+                        if (rc)
+                                GOTO(out_quotactl, rc);
+                        else
+                                qctl->qc_cmd = cmd;
+                } else {
+                        struct obd_quotactl *oqctl;
+
+                        OBD_ALLOC_PTR(oqctl);
+                        if (!oqctl)
+                                GOTO(out_quotactl, rc = -ENOMEM);
+
+                        QCTL_COPY(oqctl, qctl);
+                        rc = obd_quotactl(sbi->ll_md_exp, oqctl);
+                        if (rc) {
+                                if (rc != -EBUSY && cmd == Q_QUOTAON) {
+                                        oqctl->qc_cmd = Q_QUOTAOFF;
+                                        obd_quotactl(sbi->ll_md_exp, oqctl);
+                                }
+                                OBD_FREE_PTR(oqctl);
+                                GOTO(out_quotactl, rc);
+                        } else {
+                                QCTL_COPY(qctl, oqctl);
+                                OBD_FREE_PTR(oqctl);
+                        }
                 }
 
-                QCTL_COPY(qctl, oqctl);
-
                 if (copy_to_user((void *)arg, qctl, sizeof(*qctl)))
                         rc = -EFAULT;
+
         out_quotactl:
                 OBD_FREE_PTR(qctl);
-                OBD_FREE_PTR(oqctl);
                 RETURN(rc);
         }
-#endif /* HAVE_QUOTA_SUPPORT */
         case OBD_IOC_GETNAME: {
                 struct obd_device *obd = class_exp2obd(sbi->ll_dt_exp);
                 if (!obd)
@@ -1202,6 +1193,27 @@ static int ll_dir_ioctl(struct inode *inode, struct file *file,
                 RETURN(0);
         }
 #endif
+        case LL_IOC_GETOBDCOUNT: {
+                int count;
+
+                if (copy_from_user(&count, (int *)arg, sizeof(int)))
+                        RETURN(-EFAULT);
+
+                if (!count) {
+                        /* get ost count */
+                        struct lov_obd *lov = &sbi->ll_dt_exp->exp_obd->u.lov;
+                        count = lov->desc.ld_tgt_count;
+                } else {
+                        /* get mdt count */
+                        struct lmv_obd *lmv = &sbi->ll_md_exp->exp_obd->u.lmv;
+                        count = lmv->desc.ld_tgt_count;
+                }
+
+                if (copy_to_user((int *)arg, &count, sizeof(int)))
+                        RETURN(-EFAULT);
+
+                RETURN(0);
+        }
         default:
                 RETURN(obd_iocontrol(cmd, sbi->ll_dt_exp,0,NULL,(void *)arg));
         }
index 818008a..1a7bd1f 100644 (file)
@@ -157,9 +157,10 @@ static void ll_delete_capa(struct obd_capa *ocapa)
         }
 
         DEBUG_CAPA(D_SEC, &ocapa->c_capa, "free client");
-        list_del(&ocapa->c_list);
+        list_del_init(&ocapa->c_list);
         capa_count[CAPA_SITE_CLIENT]--;
-        free_capa(ocapa);
+        /* release the ref when alloc */
+        capa_put(ocapa);
 }
 
 /* three places where client capa is deleted:
@@ -238,7 +239,6 @@ static int capa_thread_main(void *unused)
                         capa_get(ocapa);
                         ll_capa_renewed++;
                         spin_unlock(&capa_lock);
-
                         rc = md_renew_capa(ll_i2mdexp(inode), ocapa,
                                            ll_update_capa);
                         spin_lock(&capa_lock);
@@ -259,7 +259,7 @@ static int capa_thread_main(void *unused)
                                 break;
                         }
 
-                        if (atomic_read(&ocapa->c_refc)) {
+                        if (atomic_read(&ocapa->c_refc) > 1) {
                                 DEBUG_CAPA(D_SEC, &ocapa->c_capa,
                                            "expired(c_refc %d), don't release",
                                            atomic_read(&ocapa->c_refc));
@@ -312,27 +312,6 @@ void ll_capa_thread_stop(void)
                    ll_capa_thread.t_flags & SVC_STOPPED);
 }
 
-static struct obd_capa *do_lookup_oss_capa(struct inode *inode, int opc)
-{
-        struct ll_inode_info *lli = ll_i2info(inode);
-        struct obd_capa *ocapa;
-
-        /* inside capa_lock */
-        list_for_each_entry(ocapa, &lli->lli_oss_capas, u.cli.lli_list) {
-                if ((capa_opc(&ocapa->c_capa) & opc) != opc)
-                        continue;
-
-                LASSERT(lu_fid_eq(capa_fid(&ocapa->c_capa),
-                                  ll_inode2fid(inode)));
-                LASSERT(ocapa->c_site == CAPA_SITE_CLIENT);
-
-                DEBUG_CAPA(D_SEC, &ocapa->c_capa, "found client");
-                return ocapa;
-        }
-
-        return NULL;
-}
-
 struct obd_capa *ll_osscapa_get(struct inode *inode, __u64 opc)
 {
         struct ll_inode_info *lli = ll_i2info(inode);
@@ -353,14 +332,17 @@ struct obd_capa *ll_osscapa_get(struct inode *inode, __u64 opc)
                         continue;
                 if ((opc & CAPA_OPC_OSS_WRITE) &&
                     capa_opc_supported(&ocapa->c_capa, CAPA_OPC_OSS_WRITE)) {
-                        found = 1; break;
+                        found = 1;
+                        break;
                 } else if ((opc & CAPA_OPC_OSS_READ) &&
                            capa_opc_supported(&ocapa->c_capa,
                                               CAPA_OPC_OSS_READ)) {
-                        found = 1; break;
+                        found = 1;
+                        break;
                 } else if ((opc & CAPA_OPC_OSS_TRUNC) &&
                            capa_opc_supported(&ocapa->c_capa, opc)) {
-                        found = 1; break;
+                        found = 1;
+                        break;
                 }
         }
 
@@ -429,12 +411,33 @@ static struct obd_capa *do_add_mds_capa(struct inode *inode,
 
                 DEBUG_CAPA(D_SEC, capa, "update MDS");
 
-                free_capa(ocapa);
+                capa_put(ocapa);
                 ocapa = old;
         }
         return ocapa;
 }
 
+static struct obd_capa *do_lookup_oss_capa(struct inode *inode, int opc)
+{
+        struct ll_inode_info *lli = ll_i2info(inode);
+        struct obd_capa *ocapa;
+
+        /* inside capa_lock */
+        list_for_each_entry(ocapa, &lli->lli_oss_capas, u.cli.lli_list) {
+                if ((capa_opc(&ocapa->c_capa) & opc) != opc)
+                        continue;
+
+                LASSERT(lu_fid_eq(capa_fid(&ocapa->c_capa),
+                                  ll_inode2fid(inode)));
+                LASSERT(ocapa->c_site == CAPA_SITE_CLIENT);
+
+                DEBUG_CAPA(D_SEC, &ocapa->c_capa, "found client");
+                return ocapa;
+        }
+
+        return NULL;
+}
+
 static inline void inode_add_oss_capa(struct inode *inode,
                                       struct obd_capa *ocapa)
 {
@@ -479,7 +482,7 @@ static struct obd_capa *do_add_oss_capa(struct inode *inode,
 
                 DEBUG_CAPA(D_SEC, capa, "update OSS");
 
-                free_capa(ocapa);
+                capa_put(ocapa);
                 ocapa = old;
         }
 
@@ -496,7 +499,7 @@ struct obd_capa *ll_add_capa(struct inode *inode, struct obd_capa *ocapa)
         /* truncate capa won't renew */
         if (ocapa->c_capa.lc_opc != CAPA_OPC_OSS_TRUNC) {
                 set_capa_expiry(ocapa);
-                list_del(&ocapa->c_list);
+                list_del_init(&ocapa->c_list);
                 sort_add_capa(ocapa, ll_capa_list);
 
                 update_capa_timer(ocapa, capa_renewal_time(ocapa));
@@ -547,18 +550,18 @@ int ll_update_capa(struct obd_capa *ocapa, struct lustre_capa *capa)
                         }
                 }
 
-                list_del(&ocapa->c_list);
+                list_del_init(&ocapa->c_list);
                 sort_add_capa(ocapa, &ll_idle_capas);
                 spin_unlock(&capa_lock);
 
                 capa_put(ocapa);
                 iput(inode);
-                return rc;
+                RETURN(rc);
         }
 
         spin_lock(&ocapa->c_lock);
         LASSERT(!memcmp(&ocapa->c_capa, capa,
-                        offsetof(struct lustre_capa, lc_flags)));
+                        offsetof(struct lustre_capa, lc_opc)));
         ocapa->c_capa = *capa;
         set_capa_expiry(ocapa);
         spin_unlock(&ocapa->c_lock);
@@ -616,10 +619,13 @@ void ll_truncate_free_capa(struct obd_capa *ocapa)
         LASSERT(ocapa->c_capa.lc_opc & CAPA_OPC_OSS_TRUNC);
         DEBUG_CAPA(D_SEC, &ocapa->c_capa, "free truncate");
 
+        /* release ref when find */
         capa_put(ocapa);
-        spin_lock(&capa_lock);
-        ll_delete_capa(ocapa);
-        spin_unlock(&capa_lock);
+        if (likely(ocapa->c_capa.lc_opc == CAPA_OPC_OSS_TRUNC)) {
+                spin_lock(&capa_lock);
+                ll_delete_capa(ocapa);
+                spin_unlock(&capa_lock);
+        }
 }
 
 void ll_clear_inode_capas(struct inode *inode)
index 3ed9c85..4542588 100644 (file)
@@ -232,7 +232,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt)
                                   OBD_CONNECT_VERSION  | OBD_CONNECT_MDS_CAPA |
                                   OBD_CONNECT_OSS_CAPA | OBD_CONNECT_CANCELSET|
                                   OBD_CONNECT_FID      | OBD_CONNECT_AT |
-                                  OBD_CONNECT_LOV_V3;
+                                  OBD_CONNECT_LOV_V3 | OBD_CONNECT_RMT_CLIENT;
 
 #ifdef HAVE_LRU_RESIZE_SUPPORT
         if (sbi->ll_flags & LL_SBI_LRU_RESIZE)
@@ -263,13 +263,8 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt)
 
         /* real client */
         data->ocd_connect_flags |= OBD_CONNECT_REAL;
-        if (sbi->ll_flags & LL_SBI_RMT_CLIENT) {
-                data->ocd_connect_flags &= ~OBD_CONNECT_LCL_CLIENT;
-                data->ocd_connect_flags |= OBD_CONNECT_RMT_CLIENT;
-        } else {
-                data->ocd_connect_flags &= ~OBD_CONNECT_RMT_CLIENT;
-                data->ocd_connect_flags |= OBD_CONNECT_LCL_CLIENT;
-        }
+        if (sbi->ll_flags & LL_SBI_RMT_CLIENT)
+                data->ocd_connect_flags |= OBD_CONNECT_RMT_CLIENT_FORCE;
 
         err = obd_connect(NULL, &md_conn, obd, &sbi->ll_sb_uuid, data, NULL);
         if (err == -EBUSY) {
@@ -347,21 +342,16 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt)
         if (data->ocd_connect_flags & OBD_CONNECT_JOIN)
                 sbi->ll_flags |= LL_SBI_JOIN;
 
-        if (sbi->ll_flags & LL_SBI_RMT_CLIENT) {
-                if (!(data->ocd_connect_flags & OBD_CONNECT_RMT_CLIENT)) {
-                        /* sometimes local client claims to be remote, but mdt
-                         * will disagree when client gss not applied. */
-                        LCONSOLE_INFO("client claims to be remote, but server "
-                                      "rejected, forced to be local.\n");
-                        sbi->ll_flags &= ~LL_SBI_RMT_CLIENT;
+        if (data->ocd_connect_flags & OBD_CONNECT_RMT_CLIENT) {
+                if (!(sbi->ll_flags & LL_SBI_RMT_CLIENT)) {
+                        sbi->ll_flags |= LL_SBI_RMT_CLIENT;
+                        LCONSOLE_INFO("client is set as remote by default.\n");
                 }
         } else {
-                if (!(data->ocd_connect_flags & OBD_CONNECT_LCL_CLIENT)) {
-                        /* with gss applied, remote client can not claim to be
-                         * local, so mdt maybe force client to be remote. */
-                        LCONSOLE_INFO("client claims to be local, but server "
-                                      "rejected, forced to be remote.\n");
-                        sbi->ll_flags |= LL_SBI_RMT_CLIENT;
+                if (sbi->ll_flags & LL_SBI_RMT_CLIENT) {
+                        sbi->ll_flags &= ~LL_SBI_RMT_CLIENT;
+                        LCONSOLE_INFO("client claims to be remote, but server "
+                                      "rejected, forced to be local.\n");
                 }
         }
 
@@ -385,9 +375,8 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt)
                                   OBD_CONNECT_REQPORTAL | OBD_CONNECT_BRW_SIZE |
                                   OBD_CONNECT_CANCELSET | OBD_CONNECT_FID      |
                                   OBD_CONNECT_SRVLOCK   | OBD_CONNECT_TRUNCLOCK|
-                                  OBD_CONNECT_AT;
-        if (sbi->ll_flags & LL_SBI_OSS_CAPA)
-                data->ocd_connect_flags |= OBD_CONNECT_OSS_CAPA;
+                                  OBD_CONNECT_AT | OBD_CONNECT_RMT_CLIENT |
+                                  OBD_CONNECT_OSS_CAPA;
 
         if (!OBD_FAIL_CHECK(OBD_FAIL_OSC_CONNECT_CKSUM)) {
                 /* OBD_CONNECT_CKSUM should always be set, even if checksums are
@@ -406,6 +395,9 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt)
 #ifdef HAVE_LRU_RESIZE_SUPPORT
         data->ocd_connect_flags |= OBD_CONNECT_LRU_RESIZE;
 #endif
+        if (sbi->ll_flags & LL_SBI_RMT_CLIENT)
+                data->ocd_connect_flags |= OBD_CONNECT_RMT_CLIENT_FORCE;
+
         CDEBUG(D_RPCTRACE, "ocd_connect_flags: "LPX64" ocd_version: %d "
                "ocd_grant: %d\n", data->ocd_connect_flags,
                data->ocd_version, data->ocd_grant);
@@ -471,7 +463,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt)
         err = md_getattr(sbi->ll_md_exp, &sbi->ll_root_fid, oc, valid, 0,
                          &request);
         if (oc)
-                free_capa(oc);
+                capa_put(oc);
         if (err) {
                 CERROR("md_getattr failed for root: rc = %d\n", err);
                 GOTO(out_lock_cn_cb, err);
@@ -2114,6 +2106,8 @@ int ll_process_config(struct lustre_cfg *lcfg)
            proc fns must be able to handle that! */
         rc = class_process_proc_param(PARAM_LLITE, lvars.obd_vars,
                                       lcfg, sb);
+        if (rc > 0)
+               rc = 0;
         return(rc);
 }
 
index 0933e2f..91c81c3 100644 (file)
@@ -1047,6 +1047,7 @@ int ll_objects_destroy(struct ptlrpc_request *request, struct inode *dir)
         struct lov_stripe_md *lsm = NULL;
         struct obd_trans_info oti = { 0 };
         struct obdo *oa;
+        struct obd_capa *oc = NULL;
         int rc;
         ENTRY;
 
@@ -1101,7 +1102,14 @@ int ll_objects_destroy(struct ptlrpc_request *request, struct inode *dir)
                 }
         }
 
-        rc = obd_destroy(ll_i2dtexp(dir), oa, lsm, &oti, ll_i2mdexp(dir));
+        if (body->valid & OBD_MD_FLOSSCAPA) {
+                rc = md_unpack_capa(ll_i2mdexp(dir), request, &RMF_CAPA2, &oc);
+                if (rc)
+                        GOTO(out_free_memmd, rc);
+        }
+
+        rc = obd_destroy(ll_i2dtexp(dir), oa, lsm, &oti, ll_i2mdexp(dir), oc);
+        capa_put(oc);
         OBDO_FREE(oa);
         if (rc)
                 CERROR("obd destroy objid "LPX64" error %d\n",
index ad6c65f..004218e 100644 (file)
@@ -725,12 +725,13 @@ static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp,
 {
         struct obd_device    *obddev = class_exp2obd(exp);
         struct lmv_obd       *lmv = &obddev->u.lmv;
-        int                   i;
+        int                   i = 0;
         int                   rc = 0;
         int                   set = 0;
+        int                   count = lmv->desc.ld_tgt_count;
         ENTRY;
 
-        if (lmv->desc.ld_tgt_count == 0)
+        if (count == 0)
                 RETURN(-ENOTTY);
 
         switch (cmd) {
@@ -743,7 +744,7 @@ static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp,
                 memcpy(&index, data->ioc_inlbuf2, sizeof(__u32));
                 LASSERT(data->ioc_plen1 == sizeof(struct obd_statfs));
 
-                if ((index >= lmv->desc.ld_tgt_count))
+                if ((index >= count))
                         RETURN(-ENODEV);
 
                 if (!lmv->tgts[index].ltd_active)
@@ -764,8 +765,54 @@ static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp,
                         RETURN(-EFAULT);
                 break;
         }
+        case OBD_IOC_QUOTACTL: {
+                struct if_quotactl *qctl = karg;
+                struct lmv_tgt_desc *tgt = NULL;
+                struct obd_quotactl *oqctl;
+
+                if (qctl->qc_valid == QC_MDTIDX) {
+                        if (qctl->qc_idx < 0 || count <= qctl->qc_idx)
+                                RETURN(-EINVAL);
+
+                        tgt = &lmv->tgts[qctl->qc_idx];
+                        if (!tgt->ltd_exp)
+                                RETURN(-EINVAL);
+                } else if (qctl->qc_valid == QC_UUID) {
+                        for (i = 0; i < count; i++) {
+                                tgt = &lmv->tgts[i];
+                                if (!obd_uuid_equals(&tgt->ltd_uuid,
+                                                     &qctl->obd_uuid))
+                                        continue;
+
+                                if (tgt->ltd_exp == NULL)
+                                        RETURN(-EINVAL);
+
+                                break;
+                        }
+                } else {
+                        RETURN(-EINVAL);
+                }
+
+                if (i >= count)
+                        RETURN(-EAGAIN);
+
+                LASSERT(tgt && tgt->ltd_exp);
+                OBD_ALLOC_PTR(oqctl);
+                if (!oqctl)
+                        RETURN(-ENOMEM);
+
+                QCTL_COPY(oqctl, qctl);
+                rc = obd_quotactl(tgt->ltd_exp, oqctl);
+                if (rc == 0) {
+                        QCTL_COPY(qctl, oqctl);
+                        qctl->qc_valid = QC_MDTIDX;
+                        qctl->obd_uuid = tgt->ltd_uuid;
+                }
+                OBD_FREE_PTR(oqctl);
+                break;
+        }
         default : {
-                for (i = 0; i < lmv->desc.ld_tgt_count; i++) {
+                for (i = 0; i < count; i++) {
                         int err;
 
                         if (lmv->tgts[i].ltd_exp == NULL)
@@ -773,7 +820,9 @@ static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp,
 
                         err = obd_iocontrol(cmd, lmv->tgts[i].ltd_exp, len,
                                             karg, uarg);
-                        if (err) {
+                        if (err == -ENODATA && cmd == OBD_IOC_POLL_QUOTACHECK) {
+                                RETURN(err);
+                        } else if (err) {
                                 if (lmv->tgts[i].ltd_active) {
                                         CERROR("error: iocontrol MDC %s on MDT"
                                                "idx %d cmd %x: err = %d\n",
@@ -2837,6 +2886,18 @@ static int lmv_renew_capa(struct obd_export *exp, struct obd_capa *oc,
         RETURN(rc);
 }
 
+int lmv_unpack_capa(struct obd_export *exp, struct ptlrpc_request *req,
+                    const struct req_msg_field *field, struct obd_capa **oc)
+{
+        struct obd_device *obd = exp->exp_obd;
+        struct lmv_obd *lmv = &obd->u.lmv;
+        int rc;
+
+        ENTRY;
+        rc = md_unpack_capa(lmv->tgts[0].ltd_exp, req, field, oc);
+        RETURN(rc);
+}
+
 int lmv_intent_getattr_async(struct obd_export *exp,
                              struct md_enqueue_info *minfo,
                              struct ldlm_enqueue_info *einfo)
@@ -2960,11 +3021,15 @@ struct md_ops lmv_md_ops = {
         .m_set_open_replay_data = lmv_set_open_replay_data,
         .m_clear_open_replay_data = lmv_clear_open_replay_data,
         .m_renew_capa           = lmv_renew_capa,
+        .m_unpack_capa          = lmv_unpack_capa,
         .m_get_remote_perm      = lmv_get_remote_perm,
         .m_intent_getattr_async = lmv_intent_getattr_async,
         .m_revalidate_lock      = lmv_revalidate_lock
 };
 
+static quota_interface_t *quota_interface;
+extern quota_interface_t lmv_quota_interface;
+
 int __init lmv_init(void)
 {
         struct lprocfs_static_vars lvars;
@@ -2979,10 +3044,18 @@ int __init lmv_init(void)
         }
 
         lprocfs_lmv_init_vars(&lvars);
+
+        request_module("lquota");
+        quota_interface = PORTAL_SYMBOL_GET(lmv_quota_interface);
+        init_obd_quota_ops(quota_interface, &lmv_obd_ops);
+
         rc = class_register_type(&lmv_obd_ops, &lmv_md_ops,
                                  lvars.module_vars, LUSTRE_LMV_NAME, NULL);
-        if (rc)
+        if (rc) {
+                if (quota_interface)
+                        PORTAL_SYMBOL_PUT(lmv_quota_interface);
                 cfs_mem_cache_destroy(lmv_object_cache);
+        }
 
         return rc;
 }
@@ -2990,6 +3063,9 @@ int __init lmv_init(void)
 #ifdef __KERNEL__
 static void lmv_exit(void)
 {
+        if (quota_interface)
+                PORTAL_SYMBOL_PUT(lmv_quota_interface);
+
         class_unregister_type(LUSTRE_LMV_NAME);
 
         LASSERTF(atomic_read(&lmv_object_count) == 0,
index e876da0..ea90841 100644 (file)
@@ -931,6 +931,8 @@ int lov_process_config_base(struct obd_device *obd, struct lustre_cfg *lcfg,
 
                 rc = class_process_proc_param(PARAM_LOV, lvars.obd_vars,
                                               lcfg, obd);
+               if (rc > 0)
+                       rc = 0;
                 GOTO(out, rc);
         }
         case LCFG_POOL_NEW:
@@ -1130,7 +1132,7 @@ do {
 
 static int lov_destroy(struct obd_export *exp, struct obdo *oa,
                        struct lov_stripe_md *lsm, struct obd_trans_info *oti,
-                       struct obd_export *md_exp)
+                       struct obd_export *md_exp, void *capa)
 {
         struct lov_request_set *set;
         struct obd_info oinfo;
@@ -1163,7 +1165,7 @@ static int lov_destroy(struct obd_export *exp, struct obdo *oa,
                         oti->oti_logcookies = set->set_cookies + req->rq_stripe;
 
                 err = obd_destroy(lov->lov_tgts[req->rq_idx]->ltd_exp,
-                                  req->rq_oi.oi_oa, NULL, oti, NULL);
+                                  req->rq_oi.oi_oa, NULL, oti, NULL, capa);
                 err = lov_update_common_set(set, req, err);
                 if (err) {
                         CERROR("error: destroying objid "LPX64" subobj "
@@ -1901,7 +1903,7 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
 {
         struct obd_device *obddev = class_exp2obd(exp);
         struct lov_obd *lov = &obddev->u.lov;
-        int i, rc = 0, count = lov->desc.ld_tgt_count;
+        int i = 0, rc = 0, count = lov->desc.ld_tgt_count;
         struct obd_uuid *uuidp;
         ENTRY;
 
@@ -1995,6 +1997,53 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
         case LL_IOC_LOV_SETEA:
                 rc = lov_setea(exp, karg, uarg);
                 break;
+        case OBD_IOC_QUOTACTL: {
+                struct if_quotactl *qctl = karg;
+                struct lov_tgt_desc *tgt = NULL;
+                struct obd_quotactl *oqctl;
+
+                if (qctl->qc_valid == QC_OSTIDX) {
+                        if (qctl->qc_idx < 0 || count <= qctl->qc_idx)
+                                RETURN(-EINVAL);
+
+                        tgt = lov->lov_tgts[qctl->qc_idx];
+                        if (!tgt || !tgt->ltd_exp)
+                                RETURN(-EINVAL);
+                } else if (qctl->qc_valid == QC_UUID) {
+                        for (i = 0; i < count; i++) {
+                                tgt = lov->lov_tgts[i];
+                                if (!tgt ||
+                                    !obd_uuid_equals(&tgt->ltd_uuid,
+                                                     &qctl->obd_uuid))
+                                        continue;
+
+                                if (tgt->ltd_exp == NULL)
+                                        RETURN(-EINVAL);
+
+                                break;
+                        }
+                } else {
+                        RETURN(-EINVAL);
+                }
+
+                if (i >= count)
+                        RETURN(-EAGAIN);
+
+                LASSERT(tgt && tgt->ltd_exp);
+                OBD_ALLOC_PTR(oqctl);
+                if (!oqctl)
+                        RETURN(-ENOMEM);
+
+                QCTL_COPY(oqctl, qctl);
+                rc = obd_quotactl(tgt->ltd_exp, oqctl);
+                if (rc == 0) {
+                        QCTL_COPY(qctl, oqctl);
+                        qctl->qc_valid = QC_OSTIDX;
+                        qctl->obd_uuid = tgt->ltd_uuid;
+                }
+                OBD_FREE_PTR(oqctl);
+                break;
+        }
         default: {
                 int set = 0;
 
index ba95f06..176968f 100644 (file)
@@ -620,7 +620,8 @@ cleanup:
                         continue;
 
                 sub_exp = lov->lov_tgts[req->rq_idx]->ltd_exp;
-                err = obd_destroy(sub_exp, req->rq_oi.oi_oa, NULL, oti, NULL);
+                err = obd_destroy(sub_exp, req->rq_oi.oi_oa, NULL, oti, NULL,
+                                  NULL);
                 if (err)
                         CERROR("Failed to uncreate objid "LPX64" subobj "
                                LPX64" on OST idx %d: rc = %d\n",
index 1b5311b..b80a28d 100644 (file)
@@ -60,7 +60,7 @@ sources: fsfilt_$(BACKINGFS).c
 else #SERVER
 sources:
 
-endif
+endif #SERVER
 
 ldiskfs_sed_flags = \
        -e "s/dx_hash_info/ext3_dx_hash_info/g" \
@@ -104,8 +104,7 @@ install-data-hook: $(install_data_hook)
 DIST_SOURCES = fsfilt.c fsfilt_ext3.c fsfilt_reiserfs.c lvfs_common.c \
        lvfs_internal.h lvfs_linux.c lvfs_userfs.c \
        upcall_cache.c prng.c lvfs_lib.c \
-       lustre_quota_fmt.c lustre_quota_fmt.h quotafmt_test.c \
-        # quotacheck_test.c quotactl_test.c fsfilt_ext3_quota.h
+       lustre_quota_fmt.c lustre_quota_fmt.h quotafmt_test.c
 
 MOSTLYCLEANFILES := @MOSTLYCLEANFILES@ 
 CLEANFILES = fsfilt-*.c fsfilt_ldiskfs*.c fsfilt_extN.c sources
index 25ed99c..26ed65b 100644 (file)
@@ -67,6 +67,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
@@ -723,9 +725,7 @@ static int fsfilt_ext3_statfs(struct super_block *sb, struct obd_statfs *osfs)
         int rc;
 
         memset(&sfs, 0, sizeof(sfs));
-
         rc = ll_do_statfs(sb, &sfs);
-
         if (!rc && sfs.f_bfree < sfs.f_ffree) {
                 sfs.f_files = (sfs.f_files - sfs.f_ffree) + sfs.f_bfree;
                 sfs.f_ffree = sfs.f_bfree;
@@ -883,7 +883,6 @@ static unsigned long new_blocks(handle_t *handle, struct ext3_ext_base *base,
         pblock = ext3_mb_new_blocks(handle, &ar, err);
         *count = ar.len;
         return pblock;
-
 }
 #endif
 
@@ -1315,19 +1314,37 @@ static int fsfilt_ext3_write_record(struct file *file, void *buf, int bufsize,
 
 static int fsfilt_ext3_setup(struct super_block *sb)
 {
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6)) && \
+     defined(HAVE_QUOTA_SUPPORT)) || defined(S_PDIROPS)
+        struct ext3_sb_info *sbi = EXT3_SB(sb);
 #if 0
-        EXT3_SB(sb)->dx_lock = fsfilt_ext3_dx_lock;
-        EXT3_SB(sb)->dx_unlock = fsfilt_ext3_dx_unlock;
+        sbi->dx_lock = fsfilt_ext3_dx_lock;
+        sbi->dx_unlock = fsfilt_ext3_dx_unlock;
+#endif
 #endif
 #ifdef S_PDIROPS
         CWARN("Enabling PDIROPS\n");
-        set_opt(EXT3_SB(sb)->s_mount_opt, PDIROPS);
+        set_opt(sbi->s_mount_opt, PDIROPS);
         sb->s_flags |= S_PDIROPS;
 #endif
         if (!EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_DIR_INDEX))
                 CWARN("filesystem doesn't have dir_index feature enabled\n");
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)) && defined(HAVE_QUOTA_SUPPORT)
-        set_opt(EXT3_SB(sb)->s_mount_opt, QUOTA);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6)) && defined(HAVE_QUOTA_SUPPORT)
+        /* enable journaled quota support */
+        /* kfreed in ext3_put_super() */
+        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.reserved", GFP_KERNEL);
+        if (!sbi->s_qf_names[GRPQUOTA]) {
+                kfree(sbi->s_qf_names[USRQUOTA]);
+                sbi->s_qf_names[USRQUOTA] = NULL;
+                return -ENOMEM;
+        }
+        sbi->s_jquota_fmt = QFMT_VFS_V0;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13))
+        set_opt(sbi->s_mount_opt, QUOTA);
+#endif
 #endif
         return 0;
 }
@@ -1363,8 +1380,7 @@ 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" };
-
+#ifdef HAVE_QUOTA_SUPPORT
 #define DQINFO_COPY(out, in)                    \
 do {                                            \
         Q_COPY(out, in, dqi_bgrace);            \
@@ -1386,8 +1402,6 @@ do {                                            \
         Q_COPY(out, in, dqb_valid);             \
 } while (0)
 
-
-
 static int fsfilt_ext3_quotactl(struct super_block *sb,
                                 struct obd_quotactl *oqc)
 {
@@ -1419,10 +1433,15 @@ static int fsfilt_ext3_quotactl(struct super_block *sb,
                                 continue;
 
                         if (oqc->qc_cmd == Q_QUOTAON) {
+                                char *name[MAXQUOTAS] = LUSTRE_OPQFILES_NAMES_V2;
+
+                                LASSERT(oqc->qc_id == LUSTRE_QUOTA_V2);
+
                                 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[i]);
                         } else if (oqc->qc_cmd == Q_QUOTAOFF) {
                                 if (!qcop->quota_off)
                                         GOTO(out, rc = -ENOSYS);
@@ -1455,14 +1474,38 @@ static int fsfilt_ext3_quotactl(struct super_block *sb,
                 if (!qcop->get_dqblk)
                         GOTO(out, rc = -ENOSYS);
                 rc = qcop->get_dqblk(sb, oqc->qc_type, oqc->qc_id, dqblk);
+                if (!rc)
+                        dqblk->dqb_valid = QIF_LIMITS | QIF_USAGE;
                 break;
         case Q_SYNC:
                 if (!sb->s_qcop->quota_sync)
                         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;
+                        char *name[MAXQUOTAS] = LUSTRE_OPQFILES_NAMES_V2;
+
+                        LASSERT(oqc->qc_id == LUSTRE_QUOTA_V2);
+
+                        if (!Q_TYPESET(oqc, i))
+                                continue;
+
+                        fp = filp_open(name[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[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:
@@ -1473,26 +1516,26 @@ out:
         OBD_FREE_PTR(dqblk);
 
         if (rc)
-                CDEBUG(D_QUOTA, "quotactl command %#x, id %u, type %d "
+                CDEBUG(D_QUOTA, "quotactl command %#x, id %u, type %u "
                                 "failed: %d\n",
                        oqc->qc_cmd, oqc->qc_id, oqc->qc_type, rc);
         RETURN(rc);
 }
 
 struct chk_dqblk{
-        struct hlist_node       dqb_hash;        /* quotacheck hash */
-        struct list_head        dqb_list;        /* in list also */
-        qid_t                   dqb_id;          /* uid/gid */
-        short                   dqb_type;        /* USRQUOTA/GRPQUOTA */
-        __u32                   dqb_bhardlimit;  /* block hard limit */
-        __u32                   dqb_bsoftlimit;  /* block soft limit */
-        qsize_t                 dqb_curspace;    /* current space */
-        __u32                   dqb_ihardlimit;  /* inode hard limit */
-        __u32                   dqb_isoftlimit;  /* inode soft limit */
-        __u32                   dqb_curinodes;   /* current inodes */
-        __u64                   dqb_btime;       /* block grace time */
-        __u64                   dqb_itime;       /* inode grace time */
-        __u32                   dqb_valid;       /* flag for above fields */
+        struct hlist_node       dqb_hash;        /** quotacheck hash */
+        struct list_head        dqb_list;        /** in list also */
+        qid_t                   dqb_id;          /** uid/gid */
+        short                   dqb_type;        /** USRQUOTA/GRPQUOTA */
+        qsize_t                 dqb_bhardlimit;  /** block hard limit */
+        qsize_t                 dqb_bsoftlimit;  /** block soft limit */
+        qsize_t                 dqb_curspace;    /** current space */
+        qsize_t                 dqb_ihardlimit;  /** inode hard limit */
+        qsize_t                 dqb_isoftlimit;  /** inode soft limit */
+        qsize_t                 dqb_curinodes;   /** current inodes */
+        __u64                   dqb_btime;       /** block grace time */
+        __u64                   dqb_itime;       /** inode grace time */
+        __u32                   dqb_valid;       /** flag for above fields */
 };
 
 static inline unsigned int chkquot_hash(qid_t id, int type)
@@ -1568,7 +1611,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;
@@ -1578,7 +1621,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);
 
@@ -1700,24 +1743,8 @@ static int add_inode_quota(struct inode *inode, struct qchk_ctxt *qctxt,
         return rc;
 }
 
-static int v2_write_dqheader(struct file *f, int type)
-{
-        static const __u32 quota_magics[] = V2_INITQMAGICS;
-        static const __u32 quota_versions[] = V2_INITQVERSIONS;
-        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 v2_write_dqinfo(struct file *f, int type, struct if_dqinfo *info)
+static int v3_write_dqinfo(struct file *f, int type, struct if_dqinfo *info)
 {
         struct v2_disk_dqinfo dqinfo;
         __u32 blocks = V2_DQTREEOFF + 1;
@@ -1741,6 +1768,22 @@ static int v2_write_dqinfo(struct file *f, int type, struct if_dqinfo *info)
         return cfs_user_write(f, (char *)&dqinfo, sizeof(dqinfo), &offset);
 }
 
+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);
+}
+
 static int create_new_quota_files(struct qchk_ctxt *qctxt,
                                   struct obd_quotactl *oqc)
 {
@@ -1751,32 +1794,36 @@ 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_V2;
 
                 if (!Q_TYPESET(oqc, i))
                         continue;
 
-                file = filp_open(op_quotafile[i], O_RDWR | O_CREAT | O_TRUNC,
-                                 0644);
+                LASSERT(oqc->qc_id == LUSTRE_QUOTA_V2);
+
+                file = filp_open(name[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[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[i]);
                         filp_close(file, 0);
                         GOTO(out, rc = -EINVAL);
                 }
 
-                rc = v2_write_dqheader(file, i);
+                DQUOT_DROP(file->f_dentry->d_inode);
+
+                rc = v3_write_dqheader(file, i);
                 if (rc) {
                         filp_close(file, 0);
                         GOTO(out, rc);
                 }
 
-                rc = v2_write_dqinfo(file, i, info);
+                rc = v3_write_dqinfo(file, i, info);
                 filp_close(file, 0);
                 if (rc)
                         GOTO(out, rc);
@@ -1872,12 +1919,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);
@@ -1945,14 +1992,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);
@@ -1960,7 +2007,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)
@@ -1969,7 +2016,6 @@ out:
         RETURN(rc);
 }
 
-#ifdef HAVE_QUOTA_SUPPORT
 static int fsfilt_ext3_quotainfo(struct lustre_quota_info *lqi, int type,
                                  int cmd)
 {
@@ -1994,9 +2040,15 @@ static int fsfilt_ext3_quotainfo(struct lustre_quota_info *lqi, int type,
         case QFILE_INIT_INFO:
                 rc = lustre_init_quota_info(lqi, type);
                 break;
+        case QFILE_CONVERT:
+                rc = -ENOTSUPP;
+                CERROR("quota CONVERT command is not supported\n");
+                break;
         default:
-                CERROR("Unsupported admin quota file cmd %d\n", cmd);
-                LBUG();
+                rc = -ENOTSUPP;
+                CERROR("Unsupported admin quota file cmd %d\n"
+                       "Are lquota.ko and fsfilt_ldiskfs.ko modules in sync?\n",
+                       cmd);
                 break;
         }
         RETURN(rc);
@@ -2076,13 +2128,13 @@ static struct fsfilt_operations fsfilt_ext3_ops = {
         .fs_setup               = fsfilt_ext3_setup,
         .fs_send_bio            = fsfilt_ext3_send_bio,
         .fs_get_op_len          = fsfilt_ext3_get_op_len,
-        .fs_quotactl            = fsfilt_ext3_quotactl,
-        .fs_quotacheck          = fsfilt_ext3_quotacheck,
 #ifdef HAVE_DISK_INODE_VERSION
         .fs_get_version         = fsfilt_ext3_get_version,
         .fs_set_version         = fsfilt_ext3_set_version,
 #endif
 #ifdef HAVE_QUOTA_SUPPORT
+        .fs_quotactl            = fsfilt_ext3_quotactl,
+        .fs_quotacheck          = fsfilt_ext3_quotacheck,
         .fs_quotainfo           = fsfilt_ext3_quotainfo,
         .fs_qids                = fsfilt_ext3_qids,
         .fs_dquot               = fsfilt_ext3_dquot,
index 2f58e2a..83db369 100644 (file)
@@ -184,9 +184,7 @@ static int fsfilt_reiserfs_statfs(struct super_block *sb,
         int rc;
 
         memset(&sfs, 0, sizeof(sfs));
-
         rc = ll_do_statfs(sb, &sfs);
-
         statfs_pack(osfs, &sfs);
         return rc;
 }
index b0ddb5c..ee713e4 100644 (file)
@@ -39,7 +39,6 @@
  * from linux/fs/quota_v2.c
  */
 
-
 #ifndef EXPORT_SYMTAB
 # define EXPORT_SYMTAB
 #endif
 #include <asm/uaccess.h>
 
 #include <lustre_quota.h>
+#include <obd_support.h>
 #include "lustre_quota_fmt.h"
 
-typedef char *dqbuf_t;
+#ifdef HAVE_QUOTA_SUPPORT
+
+static const uint lustre_initqversions[][MAXQUOTAS] = {
+        [LUSTRE_QUOTA_V2] = LUSTRE_INITQVERSIONS_V2
+};
+
+static const int lustre_dqstrinblk[] = {
+        [LUSTRE_QUOTA_V2] = LUSTRE_DQSTRINBLK_V2
+};
 
-#define GETIDINDEX(id, depth) (((id) >> ((LUSTRE_DQTREEDEPTH-(depth)-1)*8)) & 0xff)
-#define GETENTRIES(buf) ((struct lustre_disk_dqblk *)(((char *)buf)+sizeof(struct lustre_disk_dqdbheader)))
+static const int lustre_disk_dqblk_sz[] = {
+        [LUSTRE_QUOTA_V2] = sizeof(struct lustre_disk_dqblk_v2)
+};
 
-static int check_quota_file(struct file *f, struct inode *inode, int type)
+int check_quota_file(struct file *f, struct inode *inode, int type, 
+                     lustre_quota_version_t version)
 {
         struct lustre_disk_dqheader dqhead;
         mm_segment_t fs;
         ssize_t size;
         loff_t offset = 0;
         static const uint quota_magics[] = LUSTRE_INITQMAGICS;
-        static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
+        const uint *quota_versions = lustre_initqversions[version];
 
         if (f) {
                 fs = get_fs();
@@ -90,27 +100,26 @@ static int check_quota_file(struct file *f, struct inode *inode, int type)
 #endif
         }
         if (size != sizeof(struct lustre_disk_dqheader))
-                return 0;
+                return -EINVAL;
         if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
             le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
-                return 0;
-        return 1;
+                return -EINVAL;
+        return 0;
 }
 
-/* Check whether given file is really lustre admin quotafile */
+/**
+ * Check whether given file is really lustre admin quotafile
+ */
 int lustre_check_quota_file(struct lustre_quota_info *lqi, int type)
 {
         struct file *f = lqi->qi_files[type];
-        return check_quota_file(f, NULL, type);
+        return check_quota_file(f, NULL, type, lqi->qi_version);
 }
 
-/* Read information header from quota file */
-int lustre_read_quota_info(struct lustre_quota_info *lqi, int type)
+int lustre_read_quota_file_info(struct file* f, struct lustre_mem_dqinfo* info)
 {
         mm_segment_t fs;
         struct lustre_disk_dqinfo dinfo;
-        struct lustre_mem_dqinfo *info = &lqi->qi_info[type];
-        struct file *f = lqi->qi_files[type];
         ssize_t size;
         loff_t offset = LUSTRE_DQINFOOFF;
 
@@ -120,9 +129,9 @@ int lustre_read_quota_info(struct lustre_quota_info *lqi, int type)
                              sizeof(struct lustre_disk_dqinfo), &offset);
         set_fs(fs);
         if (size != sizeof(struct lustre_disk_dqinfo)) {
-                CDEBUG(D_WARNING, "Can't read info structure on device %s.\n",
+                CDEBUG(D_ERROR, "Can't read info structure on device %s.\n",
                        f->f_vfsmnt->mnt_sb->s_id);
-                return -1;
+                return -EINVAL;
         }
         info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
         info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
@@ -133,7 +142,17 @@ int lustre_read_quota_info(struct lustre_quota_info *lqi, int type)
         return 0;
 }
 
-/* Write information header to quota file */
+/**
+ * Read information header from quota file
+ */
+int lustre_read_quota_info(struct lustre_quota_info *lqi, int type)
+{
+        return lustre_read_quota_file_info(lqi->qi_files[type], &lqi->qi_info[type]);
+}
+
+/**
+ * Write information header to quota file
+ */
 int lustre_write_quota_info(struct lustre_quota_info *lqi, int type)
 {
         mm_segment_t fs;
@@ -164,33 +183,44 @@ int lustre_write_quota_info(struct lustre_quota_info *lqi, int type)
         return 0;
 }
 
-static void disk2memdqb(struct mem_dqblk *m, struct lustre_disk_dqblk *d)
+void disk2memdqb(struct lustre_mem_dqblk *m, void *d,
+                 lustre_quota_version_t version)
 {
-        m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
-        m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
-        m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
-        m->dqb_itime = le64_to_cpu(d->dqb_itime);
-        m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit);
-        m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit);
-        m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
-        m->dqb_btime = le64_to_cpu(d->dqb_btime);
+        struct lustre_disk_dqblk_v2 *dqblk = (struct lustre_disk_dqblk_v2 *)d;
+
+        LASSERT(version == LUSTRE_QUOTA_V2);
+
+        m->dqb_ihardlimit = le64_to_cpu(dqblk->dqb_ihardlimit);
+        m->dqb_isoftlimit = le64_to_cpu(dqblk->dqb_isoftlimit);
+        m->dqb_curinodes = le64_to_cpu(dqblk->dqb_curinodes);
+        m->dqb_itime = le64_to_cpu(dqblk->dqb_itime);
+        m->dqb_bhardlimit = le64_to_cpu(dqblk->dqb_bhardlimit);
+        m->dqb_bsoftlimit = le64_to_cpu(dqblk->dqb_bsoftlimit);
+        m->dqb_curspace = le64_to_cpu(dqblk->dqb_curspace);
+        m->dqb_btime = le64_to_cpu(dqblk->dqb_btime);
 }
 
-static void mem2diskdqb(struct lustre_disk_dqblk *d, struct mem_dqblk *m,
-                        qid_t id)
+static int mem2diskdqb(void *d, struct lustre_mem_dqblk *m,
+                       qid_t id, lustre_quota_version_t version)
 {
-        d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
-        d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
-        d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
-        d->dqb_itime = cpu_to_le64(m->dqb_itime);
-        d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit);
-        d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit);
-        d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
-        d->dqb_btime = cpu_to_le64(m->dqb_btime);
-        d->dqb_id = cpu_to_le32(id);
+        struct lustre_disk_dqblk_v2 *dqblk = (struct lustre_disk_dqblk_v2 *)d;
+
+        LASSERT(version == LUSTRE_QUOTA_V2);
+
+        dqblk->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
+        dqblk->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
+        dqblk->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
+        dqblk->dqb_itime = cpu_to_le64(m->dqb_itime);
+        dqblk->dqb_bhardlimit = cpu_to_le64(m->dqb_bhardlimit);
+        dqblk->dqb_bsoftlimit = cpu_to_le64(m->dqb_bsoftlimit);
+        dqblk->dqb_curspace = cpu_to_le64(m->dqb_curspace);
+        dqblk->dqb_btime = cpu_to_le64(m->dqb_btime);
+        dqblk->dqb_id = cpu_to_le32(id);
+
+        return 0;
 }
 
-static dqbuf_t getdqbuf(void)
+dqbuf_t getdqbuf(void)
 {
         dqbuf_t buf = kmalloc(LUSTRE_DQBLKSIZE, GFP_NOFS);
         if (!buf)
@@ -199,12 +229,12 @@ static dqbuf_t getdqbuf(void)
         return buf;
 }
 
-static inline void freedqbuf(dqbuf_t buf)
+void freedqbuf(dqbuf_t buf)
 {
         kfree(buf);
 }
 
-static ssize_t read_blk(struct file *filp, uint blk, dqbuf_t buf)
+ssize_t read_blk(struct file *filp, uint blk, dqbuf_t buf)
 {
         mm_segment_t fs;
         ssize_t ret;
@@ -218,7 +248,7 @@ static ssize_t read_blk(struct file *filp, uint blk, dqbuf_t buf)
         return ret;
 }
 
-static ssize_t write_blk(struct file *filp, uint blk, dqbuf_t buf)
+ssize_t write_blk(struct file *filp, uint blk, dqbuf_t buf)
 {
         mm_segment_t fs;
         ssize_t ret;
@@ -229,18 +259,17 @@ static ssize_t write_blk(struct file *filp, uint blk, dqbuf_t buf)
         ret = filp->f_op->write(filp, (char *)buf, LUSTRE_DQBLKSIZE, &offset);
         set_fs(fs);
         return ret;
-
 }
 
-static void lustre_mark_info_dirty(struct lustre_mem_dqinfo *info)
+void lustre_mark_info_dirty(struct lustre_mem_dqinfo *info)
 {
         set_bit(DQF_INFO_DIRTY_B, &info->dqi_flags);
 }
 
-#define lustre_info_dirty(info) test_bit(DQF_INFO_DIRTY_B, &(info)->dqi_flags)
-
-/* Remove empty block from list and return it */
-static int get_free_dqblk(struct file *filp, struct lustre_mem_dqinfo *info)
+/**
+ * Remove empty block from list and return it
+ */
+int get_free_dqblk(struct file *filp, struct lustre_mem_dqinfo *info)
 {
         dqbuf_t buf = getdqbuf();
         struct lustre_disk_dqdbheader *dh =
@@ -256,7 +285,8 @@ static int get_free_dqblk(struct file *filp, struct lustre_mem_dqinfo *info)
                 info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
         } else {
                 memset(buf, 0, LUSTRE_DQBLKSIZE);
-                if ((ret = write_blk(filp, info->dqi_blocks, buf)) < 0) /* Assure block allocation... */
+                /* Assure block allocation... */
+                if ((ret = write_blk(filp, info->dqi_blocks, buf)) < 0)
                         goto out_buf;
                 blk = info->dqi_blocks++;
         }
@@ -267,9 +297,11 @@ out_buf:
         return ret;
 }
 
-/* Insert empty block to the list */
-static int put_free_dqblk(struct file *filp, struct lustre_mem_dqinfo *info,
-                          dqbuf_t buf, uint blk)
+/**
+ * Insert empty block to the list
+ */
+int put_free_dqblk(struct file *filp, struct lustre_mem_dqinfo *info,
+                   dqbuf_t buf, uint blk)
 {
         struct lustre_disk_dqdbheader *dh =
             (struct lustre_disk_dqdbheader *)buf;
@@ -286,10 +318,12 @@ static int put_free_dqblk(struct file *filp, struct lustre_mem_dqinfo *info,
         return 0;
 }
 
-/* Remove given block from the list of blocks with free entries */
-static int remove_free_dqentry(struct file *filp,
-                               struct lustre_mem_dqinfo *info, dqbuf_t buf,
-                               uint blk)
+/**
+ * Remove given block from the list of blocks with free entries
+ */
+int remove_free_dqentry(struct file *filp,
+                        struct lustre_mem_dqinfo *info, dqbuf_t buf,
+                        uint blk)
 {
         dqbuf_t tmpbuf = getdqbuf();
         struct lustre_disk_dqdbheader *dh =
@@ -321,7 +355,8 @@ static int remove_free_dqentry(struct file *filp,
         }
         freedqbuf(tmpbuf);
         dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
-        if (write_blk(filp, blk, buf) < 0)      /* No matter whether write succeeds block is out of list */
+        if (write_blk(filp, blk, buf) < 0)
+                /* No matter whether write succeeds block is out of list */
                 CDEBUG(D_ERROR, 
                        "VFS: Can't write block (%u) with free entries.\n", blk);
         return 0;
@@ -330,10 +365,12 @@ out_buf:
         return err;
 }
 
-/* Insert given block to the beginning of list with free entries */
-static int insert_free_dqentry(struct file *filp,
-                               struct lustre_mem_dqinfo *info, dqbuf_t buf,
-                               uint blk)
+/**
+ * Insert given block to the beginning of list with free entries
+ */
+int insert_free_dqentry(struct file *filp,
+          &n