default: all
-MODULES := ldiskfs #quotafmt_test
+MODULES := ldiskfs
+
+@QUOTA_TRUE@MODULES += quotafmt_test
# copy makefile over to not break patches
ext3_extra := $(wildcard @LINUX@/fs/ext3/Makefile)
ext3_sources := $(filter-out %.mod.c,$(wildcard @LINUX@/fs/ext3/*.c))
new_sources := iopen.c iopen.h extents.c mballoc.c proc.c
new_headers := ext3_extents.h
-#quotafmt_sources := lustre_quota_fmt.c
-#quotafmt_headers := lustre_quota_fmt.h
ldiskfs_patched_sources := $(notdir $(ext3_sources) $(ext3_headers)) $(new_sources) $(new_headers)
-ldiskfs_sources := $(ldiskfs_patched_sources) #$(quotafmt_sources) $(quotafmt_headers)
+ldiskfs_sources := $(ldiskfs_patched_sources)
+
+quotafmt_sources := lustre_quota_fmt.c
+quotafmt_headers := lustre_quota_fmt.h
+@QUOTA_TRUE@ldiskfs_sources += $(quotafmt_sources) $(quotafmt_headers)
ldiskfs-objs := $(filter %.o,$(ldiskfs_sources:.c=.o))
-#quotafmt-objs := quotafmt_test.o
+
+@QUOTA_TRUE@quotafmt-objs := quotafmt_test.o
EXTRA_PRE_CFLAGS := -I@LINUX@/fs -I@LUSTRE@ -I@LUSTRE@/ldiskfs
@SERVER_TRUE@subdir-m += mds obdfilter ost
@CLIENT_TRUE@subdir-m += mdc llite
+@QUOTA_TRUE@subdir-m += quota
@INCLUDE_RULES@
CLIENT_SUBDIRS := mdc llite
+QUOTA_SUBDIRS := quota
+
LIBLUSTRE_SUBDIRS := liblustre
SUBDIRS := $(ALWAYS_SUBDIRS)
SUBDIRS += $(CLIENT_SUBDIRS)
endif
+if QUOTA
+SUBDIRS += $(QUOTA_SUBDIRS)
+endif
+
# this needs to be after the client subdirs
if LIBLUSTRE
if !CLIENT
endif
DIST_SUBDIRS := $(ALWAYS_SUBDIRS) $(SERVER_SUBDIRS) $(CLIENT_SUBDIRS) \
- $(LIBLUSTRE_SUBDIRS)
+ $(LIBLUSTRE_SUBDIRS) $(QUOTA_SUBDIRS)
EXTRA_DIST = BUGS FDL kernel_patches
LC_CONFIG_BACKINGFS
fi
LC_CONFIG_PINGER
+LC_CONFIG_QUOTA
LC_STRUCT_KIOBUF
LC_FUNC_COND_RESCHED
])
#
+# LC_CONFIG_QUOTA
+#
+# whether to enable quota support
+#
+AC_DEFUN([LC_CONFIG_QUOTA],
+[AC_MSG_CHECKING([whether to enable quota support])
+AC_ARG_ENABLE([quota],
+ AC_HELP_STRING([--enable-quota],
+ [enable quota support]),
+ [],[enable_quota='yes'])
+AC_MSG_RESULT([$enable_quota])
+if test x$enable_quota != xno ; then
+ AC_DEFINE(HAVE_QUOTA_SUPPORT, 1, [Enable quota support])
+fi
+])
+
+#
# LC_CONFIGURE
#
# other configure checks
# See note there re: __ASM_X86_64_PROCESSOR_H
AC_CHECK_HEADERS([linux/quota.h])
-AC_CHECK_TYPES([struct if_dqinfo],[],[],[
-#define __ASM_X86_64_PROCESSOR_H
-#include <linux/quota.h>
-])
-
-AC_CHECK_TYPES([struct if_dqblk],[],[],[
-#define __ASM_X86_64_PROCESSOR_H
-#include <linux/quota.h>
-])
-
# liblustre/llite_lib.h
AC_CHECK_HEADERS([xtio.h file.h])
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)
])
#
lustre/ost/autoMakefile
lustre/ptlrpc/Makefile
lustre/ptlrpc/autoMakefile
+lustre/quota/Makefile
+lustre/quota/autoMakefile
lustre/scripts/Makefile
lustre/scripts/version_tag.pl
lustre/tests/Makefile
.br
.B lfs setstripe <filename> <stripe-size> <start-ost> <stripe-cnt>
.br
+.B lfs quotachown [-i] <filesystem>
+.br
+.B lfs quotacheck [-ug] <filesystem>
+.br
+.B lfs quotaon [-ugf] <filesystem>
+.br
+.B lfs quotaoff [-ug] <filesystem>
+.br
+.B lfs setquota [-u|-g] <name> <block-softlimit> <block-hardlimit> <inode-softlimit> <inode-hardlimit> <filesystem>
+.br
+.B lfs quota [-o obd_uuid] [-u|-g] <name> <filesystem>
+.br
+.B lfs setstripe <filename> <stripe-size> <start-ost> <stripe-cnt>
+.br
.B lfs check <mds| osts| servers>
.SH DESCRIPTION
.B lfs
.B getstripe
To list the striping pattern for given filename
.TP
+.B quotachown
+To change files' owner and group on OSTs of the specified filesystem
+.TP
+.B quotacheck
+To scan the specified filesystem for disk usage, and create or update quota files
+.TP
+.B quotaon
+To turn filesystem quotas on
+.TP
+.B quotaoff
+To turn filesystem quotas off
+.TP
+.B setquota
+To set filesystem quotas
+.TP
+.B quota
+To display disk usage and limits
+.TP
.B check
Display the status of MDS or OSTs (as specified in the command) or all the servers (MDS and OSTs)
.TP
.B $lfs find -r --obd OST2-UUID /mnt/lustre/
List all the files that have objects on a specific OST
.TP
+.B $lfs quotachown -i /mnt/lustre
+Change file owner and group
+.TP
+.B $lfs quotacheck -ug /mnt/lustre
+Quotacheck for user and group
+.TP
+.B $lfs quotaon -ug /mnt/lustre
+Turn quotas of user and group on
+.TP
+.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
+.TP
+.B $lfs quota -u bob /mnt/lustre
+List quotas of user `bob'
+.TP
+.B $ lfs find -r --obd OST2-UUID /mnt/lustre/
+.TP
.B $lfs check servers
Check the status of all servers(mds, osts)
.TP
NAME
\layout Description
-lfs Lustre utility to create a file with specific striping pattern
+lfs Lustre utility to create a file with specific striping pattern and manipulat
+e disk quotas
\layout Subsection
SYNOPSIS
\series bold
lfs\SpecialChar ~
check <mds| osts| servers>
+\layout Standard
+
+
+\series bold
+lfs\SpecialChar ~
+quotachog [-i] <filesystem>
+\layout Standard
+
+
+\series bold
+lfs\SpecialChar ~
+quotacheck [-ug] <filesystem>
+\layout Standard
+
+
+\series bold
+lfs\SpecialChar ~
+quotaon [-ugf] <filesystem>
+\layout Standard
+
+
+\series bold
+lfs\SpecialChar ~
+quotaoff [-ug] <filesystem>
+\layout Standard
+
+
+\series bold
+lfs\SpecialChar ~
+setquota [-u|-g] <name> <block-softlimit> <block-hardlimit> <inode-softlimit>
+ <inode-hardlimit> <filesystem>
+\layout Standard
+
+
+\series bold
+lfs\SpecialChar ~
+quota [-o obd_uuid] [-u|-g] <name> <filesystem>
\layout Subsection
DESCRIPTION
This utility can be used to create a new file with a specific striping pattern,
determine the default striping pattern, gather the extended attributes
- (object numbers and location) for a specific file.
+ (object numbers and location) for a specific file, and manipulate disk
+ quotas.
It can be invoked interactively without any arguments or in a non-interactive
mode with one of the arguements listed and explained below:
\layout List
\series bold
+quotachog
+\series default
+ Change files' owner and group on OSTs of the specified filesystem
+\layout List
+\labelwidthstring 00.00.0000
+
+
+\series bold
+quotacheck
+\series default
+ Scan the specified filesystem for disk usage, and create or update quota
+ files
+\layout List
+\labelwidthstring 00.00.0000
+
+
+\series bold
+quotaon
+\series default
+ Turn filesystem quotas on
+\layout List
+\labelwidthstring 00.00.0000
+
+
+\series bold
+quotaoff
+\series default
+ Turn filesystem quotas off
+\layout List
+\labelwidthstring 00.00.0000
+
+
+\series bold
+setquota
+\series default
+ Set filesystem quotas
+\layout List
+\labelwidthstring 00.00.0000
+
+
+\series bold
+quota
+\series default
+ Display disk usage and limits
+\layout List
+\labelwidthstring 00.00.0000
+
+
+\series bold
help
\series default
Provides brief help on the various arguments
\layout LyX-Code
$
+\layout Description
+
+Change\SpecialChar ~
+file\SpecialChar ~
+owner\SpecialChar ~
+and\SpecialChar ~
+group
+\layout LyX-Code
+
+ $lfs quotachog -i /mnt/lustre
+\layout Description
+
+Quotacheck\SpecialChar ~
+for\SpecialChar ~
+user\SpecialChar ~
+and\SpecialChar ~
+group
+\layout LyX-Code
+
+ $lfs quotacheck -ug /mnt/lustre
+\layout Description
+
+Turn\SpecialChar ~
+quotas\SpecialChar ~
+of\SpecialChar ~
+user\SpecialChar ~
+and\SpecialChar ~
+group\SpecialChar ~
+on
+\layout LyX-Code
+
+ $lfs quotaon -ug /mnt/lustre
+\layout Description
+
+Turn\SpecialChar ~
+quotas\SpecialChar ~
+of\SpecialChar ~
+user\SpecialChar ~
+and\SpecialChar ~
+group\SpecialChar ~
+off
+\layout LyX-Code
+
+ $lfs quotaoff -ug /mnt/lustre
+\layout Description
+
+Set\SpecialChar ~
+quotas\SpecialChar ~
+of\SpecialChar ~
+user\SpecialChar ~
+`bob':\SpecialChar ~
+1GB\SpecialChar ~
+block\SpecialChar ~
+quota\SpecialChar ~
+and\SpecialChar ~
+10,000\SpecialChar ~
+file\SpecialChar ~
+quota
+\layout LyX-Code
+
+ $lfs setquota -u bob 0 1000000 0 10000 /mnt/lustre
+\layout Description
+
+List\SpecialChar ~
+quotas\SpecialChar ~
+of\SpecialChar ~
+user\SpecialChar ~
+`bob'
+\layout LyX-Code
+
+ $lfs quota -u bob /mnt/lustre
\layout Subsection
BUGS
#define hlist_node list_head
#define HLIST_HEAD LIST_HEAD
#define INIT_HLIST_HEAD INIT_LIST_HEAD
+#define INIT_HLIST_NODE(p) (p)
#define hlist_del_init list_del_init
#define hlist_add_head list_add
+#define hlist_for_each list_for_each
#define hlist_for_each_safe list_for_each_safe
#endif
#define KDEVT_INIT(val) (val)
int (* fs_quotactl)(struct super_block *sb,
struct obd_quotactl *oqctl);
int (* fs_quotainfo)(struct lustre_quota_info *lqi, int type,
- int cmd);
+ int cmd, struct list_head *list);
int (* fs_dquot)(struct lustre_dquot *dquot, int cmd);
};
static inline int fsfilt_quotainfo(struct obd_device *obd,
struct lustre_quota_info *lqi,
- int type, int cmd)
+ int type, int cmd, struct list_head *list)
{
if (obd->obd_fsops->fs_quotainfo)
- return obd->obd_fsops->fs_quotainfo(lqi, type, cmd);
+ return obd->obd_fsops->fs_quotainfo(lqi, type, cmd, list);
return -ENOTSUPP;
}
extern void lustre_swab_mds_body (struct mds_body *b);
-/* XXX: same as if_dqinfo struct in kernel */
-struct obd_dqinfo {
- __u64 dqi_bgrace;
- __u64 dqi_igrace;
- __u32 dqi_flags;
- __u32 dqi_valid;
-};
-
-/* XXX: same as if_dqblk struct in kernel, plus one padding */
-struct obd_dqblk {
- __u64 dqb_bhardlimit;
- __u64 dqb_bsoftlimit;
- __u64 dqb_curspace;
- __u64 dqb_ihardlimit;
- __u64 dqb_isoftlimit;
- __u64 dqb_curinodes;
- __u64 dqb_btime;
- __u64 dqb_itime;
- __u32 dqb_valid;
- __u32 padding;
-};
-
#define Q_QUOTACHECK 0x800100
#define Q_INITQUOTA 0x800101 /* init slave limits */
#define Q_GETOINFO 0x800102 /* get obd quota info */
/* qutoa */
struct qunit_data {
- __u32 qd_id;
- __u32 qd_type;
- __u32 qd_count;
- __u32 qd_isblk; /* indicating if it's block quota */
+ __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 */
};
extern void lustre_swab_qdata(struct qunit_data *d);
} u;
};
-struct llog_fill_rec_data {
- obd_id lfd_id; /* object id */
- obd_count lfd_ogen; /* object group */
-};
-
/* llog.c - general API */
typedef int (*llog_cb_t)(struct llog_handle *, struct llog_rec_hdr *, void *);
typedef int (*llog_fill_rec_cb_t)(struct llog_rec_hdr *rec, void *data);
int llog_sync(struct llog_ctxt *ctxt, struct obd_export *exp);
int llog_add(struct llog_ctxt *ctxt, struct llog_rec_hdr *rec,
struct lov_stripe_md *lsm, struct llog_cookie *logcookies,
- int numcookies, llog_fill_rec_cb_t fill_cb);
+ int numcookies);
int llog_cancel(struct llog_ctxt *, struct lov_stripe_md *lsm,
int count, struct llog_cookie *cookies, int flags);
int llog_obd_origin_cleanup(struct llog_ctxt *ctxt);
int llog_obd_origin_add(struct llog_ctxt *ctxt,
struct llog_rec_hdr *rec, struct lov_stripe_md *lsm,
- struct llog_cookie *logcookies, int numcookies,
- llog_fill_rec_cb_t fill_cb);
+ struct llog_cookie *logcookies, int numcookies);
int llog_cat_initialize(struct obd_device *obd, int count);
int obd_llog_init(struct obd_device *obd, struct obd_device *disk_obd,
int (*lop_cleanup)(struct llog_ctxt *ctxt);
int (*lop_add)(struct llog_ctxt *ctxt, struct llog_rec_hdr *rec,
struct lov_stripe_md *lsm,
- struct llog_cookie *logcookies, int numcookies,
- llog_fill_rec_cb_t fill_cb);
+ struct llog_cookie *logcookies, int numcookies);
int (*lop_cancel)(struct llog_ctxt *ctxt, struct lov_stripe_md *lsm,
int count, struct llog_cookie *cookies, int flags);
int (*lop_connect)(struct llog_ctxt *ctxt, int count,
#define _LUSTRE_QUOTA_H
#ifdef __KERNEL__
-# include <linux/version.h>
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/quota.h>
+#include <linux/quotaops.h>
#endif
#include <linux/lustre_idl.h>
+#include <linux/lustre_net.h>
+#include <linux/lvfs.h>
+
+struct obd_device;
+struct client_obd;
+
+#ifndef NR_DQHASH
+#define NR_DQHASH 45
+#endif
#ifdef HAVE_QUOTA_SUPPORT
-#include <linux/lustre_realquota.h>
-#else
+#ifdef __KERNEL__
+
+/* structures to access admin quotafile */
struct lustre_mem_dqinfo {
+ unsigned int dqi_bgrace;
+ unsigned int dqi_igrace;
+ unsigned long dqi_flags;
+ unsigned int dqi_blocks;
+ unsigned int dqi_free_blk;
+ unsigned int dqi_free_entry;
};
struct lustre_quota_info {
+ struct file *qi_files[MAXQUOTAS];
+ struct lustre_mem_dqinfo qi_info[MAXQUOTAS];
};
+#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_dquot {
+ /* Hash list in memory, protect by dquot_hash_lock */
+ struct list_head dq_hash;
+ /* Protect the data in lustre_dquot */
+ struct semaphore dq_sem;
+ /* Use count */
+ int dq_refcnt;
+ /* 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 */
};
+struct dquot_id {
+ struct list_head di_link;
+ __u32 di_id;
+};
+
+#define QFILE_CHK 1
+#define QFILE_RD_INFO 2
+#define QFILE_WR_INFO 3
+#define QFILE_INIT_INFO 4
+#define QFILE_GET_QIDS 5
+#define QFILE_RD_DQUOT 6
+#define QFILE_WR_DQUOT 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 lustre_quota_info *lqi, int type,
+ struct list_head *list);
+#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;
}
-#ifdef __KERNEL__
static inline int lustre_read_dquot(struct lustre_dquot *dquot)
{
return 0;
{
return 0;
}
-#endif
static inline int lustre_init_quota_info(struct lustre_quota_info *lqi,
int type)
{
return 0;
}
+#endif /* KERNEL_VERSION(2,5,0) */
-struct obd_device;
+#define LL_DQUOT_OFF(sb) DQUOT_OFF(sb)
typedef int (*dqacq_handler_t) (struct obd_device * obd, struct qunit_data * qd,
int opc);
+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 */
+ 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 */
+};
+
+#else
+
+struct lustre_quota_info {
+};
+
+struct lustre_quota_ctxt {
+};
+
+#endif /* !__KERNEL__ */
+
+#else
+
+#define LL_DQUOT_OFF(sb) do {} while(0)
+
+struct lustre_quota_info {
+};
struct lustre_quota_ctxt {
};
-struct lustre_qunit {
+#endif /* !HAVE_QUOTA_SUPPORT */
+
+/* If the (quota limit < qunit * slave count), the slave which can't
+ * acquire qunit should set it's local limit as MIN_QLIMIT */
+#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 super_block;
-static inline int qctxt_init(struct lustre_quota_ctxt *qctxt,
- struct super_block *sb, dqacq_handler_t handler)
+typedef struct {
+ int (*quota_init) (void);
+ int (*quota_exit) (void);
+ int (*quota_setup) (struct obd_device *, struct lustre_cfg *);
+ int (*quota_cleanup) (struct obd_device *);
+ /* 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_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 */
+ int (*quota_enforce) (struct obd_device *, unsigned int);
+
+ /* 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 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 */
+ int (*quota_chkdq) (struct client_obd *, unsigned int, unsigned 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);
+} quota_interface_t;
+
+#define Q_COPY(out, in, member) (out)->member = (in)->member
+
+#define QUOTA_OP(interface, op) interface->quota_ ## op
+
+#define QUOTA_CHECK_OP(interface, op) \
+do { \
+ if (!interface) \
+ RETURN(0); \
+ if (!QUOTA_OP(interface, op)) { \
+ CERROR("no quota operation: " #op "\n"); \
+ RETURN(-EOPNOTSUPP); \
+ } \
+} while(0)
+
+static inline int lquota_init(quota_interface_t *interface)
{
- return 0;
+ int rc;
+ ENTRY;
+
+ QUOTA_CHECK_OP(interface, init);
+ rc = QUOTA_OP(interface, init)();
+ RETURN(rc);
}
-static inline void qctxt_cleanup(struct lustre_quota_ctxt *qctxt, int force)
+
+static inline int lquota_exit(quota_interface_t *interface)
{
- return;
+ int rc;
+ ENTRY;
+
+ QUOTA_CHECK_OP(interface, exit);
+ rc = QUOTA_OP(interface, exit)();
+ RETURN(rc);
}
-static inline int qctxt_adjust_qunit(struct obd_device *obd,
- struct lustre_quota_ctxt *qctxt,
- uid_t uid, gid_t gid, __u32 isblk)
+
+static inline int lquota_setup(quota_interface_t *interface,
+ struct obd_device *obd,
+ struct lustre_cfg *lcfg)
{
- return 0;
+ int rc;
+ ENTRY;
+
+ QUOTA_CHECK_OP(interface, setup);
+ rc = QUOTA_OP(interface, setup)(obd, lcfg);
+ RETURN(rc);
}
-static inline int qctxt_wait_on_dqacq(struct obd_device *obd,
- struct lustre_quota_ctxt *qctxt,
- uid_t uid, gid_t gid, __u32 isblk)
+
+static inline int lquota_cleanup(quota_interface_t *interface,
+ struct obd_device *obd)
{
- return 0;
+ int rc;
+ ENTRY;
+
+ QUOTA_CHECK_OP(interface, cleanup);
+ rc = QUOTA_OP(interface, cleanup)(obd);
+ RETURN(rc);
}
-struct quotacheck_info {
-};
+static inline int lquota_fs_cleanup(quota_interface_t *interface,
+ struct obd_device *obd)
+{
+ int rc;
+ ENTRY;
+
+ QUOTA_CHECK_OP(interface, fs_cleanup);
+ rc = QUOTA_OP(interface, fs_cleanup)(obd);
+ RETURN(rc);
+}
-#define LL_DQUOT_OFF(sb) do {} while(0)
+static inline int lquota_recovery(quota_interface_t *interface,
+ struct obd_device *obd)
+{
+ int rc;
+ ENTRY;
+
+ QUOTA_CHECK_OP(interface, recovery);
+ rc = QUOTA_OP(interface, recovery)(obd);
+ 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)
+{
+ int ret;
+ ENTRY;
+
+ QUOTA_CHECK_OP(interface, adjust);
+ ret = QUOTA_OP(interface, adjust)(obd, qcids, qpids, rc, opc);
+ RETURN(ret);
+}
+
+static inline int lquota_chkdq(quota_interface_t *interface,
+ struct client_obd *cli,
+ unsigned int uid, unsigned int gid)
+{
+ int rc;
+ ENTRY;
+
+ QUOTA_CHECK_OP(interface, chkdq);
+ rc = QUOTA_OP(interface, chkdq)(cli, uid, gid);
+ RETURN(rc);
+}
+
+static inline int lquota_setdq(quota_interface_t *interface,
+ struct client_obd *cli,
+ unsigned int uid, unsigned int gid,
+ obd_flag valid, obd_flag flags)
+{
+ int rc;
+ ENTRY;
+
+ QUOTA_CHECK_OP(interface, setdq);
+ rc = QUOTA_OP(interface, setdq)(cli, uid, gid, valid, flags);
+ RETURN(rc);
+}
+
+static inline int lquota_poll_check(quota_interface_t *interface,
+ struct obd_export *exp,
+ struct if_quotacheck *qchk)
+{
+ 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)
+{
+ int rc;
+ ENTRY;
+
+ QUOTA_CHECK_OP(interface, setinfo);
+ rc = QUOTA_OP(interface, setinfo)(exp, obd);
+ RETURN(rc);
+}
+
+static inline int lquota_enforce(quota_interface_t *interface,
+ struct obd_device *obd,
+ unsigned int ignore)
+{
+ int rc;
+ ENTRY;
+
+ QUOTA_CHECK_OP(interface, enforce);
+ rc = QUOTA_OP(interface, enforce)(obd, ignore);
+ RETURN(rc);
+}
+
+static inline int lquota_getflag(quota_interface_t *interface,
+ struct obd_device *obd, struct obdo *oa)
+{
+ int rc;
+ ENTRY;
+
+ QUOTA_CHECK_OP(interface, getflag);
+ 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)
+{
+ int rc;
+ ENTRY;
+
+ QUOTA_CHECK_OP(interface, acquire);
+ rc = QUOTA_OP(interface, acquire)(obd, uid, gid);
+ RETURN(rc);
+}
+
+#ifndef __KERNEL__
+extern quota_interface_t osc_quota_interface;
+extern quota_interface_t mdc_quota_interface;
+extern quota_interface_t lov_quota_interface;
+#endif
-#endif /*!HAVE_QUOTA_SUPPORT */
#endif /* _LUSTRE_QUOTA_H */
struct ost_server_data;
+/* hold common fields for "target" device */
+struct obd_device_target {
+ struct super_block *obt_sb;
+ atomic_t obt_quotachecking;
+ struct lustre_quota_ctxt obt_qctxt;
+};
+
#define FILTER_GROUP_LLOG 1
#define FILTER_GROUP_ECHO 2
};
struct filter_obd {
+ /* NB this field MUST be first */
+ struct obd_device_target fo_obt;
const char *fo_fstype;
- struct super_block *fo_sb;
struct vfsmount *fo_vfsmnt;
struct dentry *fo_dentry_O;
struct dentry **fo_dentry_O_groups;
#define OSC_MAX_DIRTY_DEFAULT 32
#define OSC_MAX_DIRTY_MB_MAX 512 /* totally arbitrary */
-enum {
- CL_QUOTACHECKING = 1,
- CL_NO_QUOTACHECK
-};
-
struct mdc_rpc_lock;
struct client_obd {
struct obd_import *cl_import;
struct osc_async_rc cl_ar;
/* used by quotacheck */
- spinlock_t cl_qchk_lock;
int cl_qchk_stat; /* quotacheck stat of the peer */
struct ptlrpc_request_pool *cl_rq_pool; /* emergency pool of requests */
};
+#define CL_NOT_QUOTACHECKED 1 /* client->cl_qchk_stat init value */
+
struct mds_obd {
+ /* NB this field MUST be first */
+ struct obd_device_target mds_obt;
struct ptlrpc_service *mds_service;
struct ptlrpc_service *mds_setattr_service;
struct ptlrpc_service *mds_readpage_service;
- struct super_block *mds_sb;
struct vfsmount *mds_vfsmnt;
struct dentry *mds_fid_de;
int mds_max_mdsize;
unsigned long *mds_client_bitmap;
struct semaphore mds_orphan_recovery_sem;
struct upcall_cache *mds_group_hash;
+
struct lustre_quota_info mds_quota_info;
- struct lustre_quota_ctxt mds_quota_ctxt;
- atomic_t mds_quotachecking;
+ struct semaphore mds_qonoff_sem;
struct semaphore mds_health_sem;
unsigned long mds_lov_objids_valid:1,
mds_fl_user_xattr:1,
time_t obd_recovery_end;
union {
+ struct obd_device_target obt;
struct filter_obd filter;
struct mds_obd mds;
struct client_obd cli;
}
}
+static inline void init_obd_quota_ops(quota_interface_t *interface,
+ struct obd_ops *obd_ops)
+{
+ if (!interface)
+ return;
+
+ LASSERT(obd_ops);
+ obd_ops->o_quotacheck = QUOTA_OP(interface, check);
+ obd_ops->o_quotactl = QUOTA_OP(interface, ctl);
+}
+
#endif /* __OBD_H */
return oa;
}
-/* qunit hash stuff */
-extern kmem_cache_t *qunit_cachep;
-extern struct list_head qunit_hash[];
-extern spinlock_t qunit_hash_lock;
-
static inline void obdo_free(struct obdo *oa)
{
OBD_SLAB_FREE(oa, obdo_cachep, sizeof(*oa));
#include <linux/obd_class.h>
+#define LUSTRE_FILTER_NAME "obdfilter"
#define LUSTRE_OST_NAME "ost"
#define LUSTRE_OSC_NAME "osc"
#define LUSTRE_SANOSC_NAME "sanosc"
#define OBD_FAIL_OBD_LOG_CANCEL_NET 0x601
#define OBD_FAIL_OBD_LOGD_NET 0x602
#define OBD_FAIL_OBD_QC_CALLBACK_NET 0x603
+#define OBD_FAIL_OBD_DQACQ 0x604
#define OBD_FAIL_TGT_REPLY_NET 0x700
#define OBD_FAIL_TGT_CONN_RACE 0x701
#include <lustre/lustre_user.h>
+typedef void (*llapi_cb_t)(char *obd_type_name, char *obd_name, char *obd_uuid, void *args);
+
/* liblustreapi.c */
extern int llapi_file_create(char *name, long stripe_size, int stripe_offset,
int stripe_count, int stripe_pattern);
extern int llapi_catinfo(char *dir, char *keyword, char *node_name);
extern int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count);
extern int llapi_is_lustre_mnttype(char *type);
+extern int llapi_quotachown(char *path, int flag);
extern int llapi_quotacheck(char *mnt, int check_type);
extern int llapi_poll_quotacheck(char *mnt, struct if_quotacheck *qchk);
extern int llapi_quotactl(char *mnt, struct if_quotactl *qctl);
-extern int llapi_quotachog(char *path, int flag);
+extern int llapi_target_iterate(int type_num, char **obd_type, void *args, llapi_cb_t cb);
#endif
uuid->uuid[sizeof(*uuid) - 1] = '\0';
}
+#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 */
+
#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[10];
+ __u8 obd_type[16];
struct obd_uuid obd_uuid;
- int stat;
};
#define MDS_GRP_DOWNCALL_MAGIC 0x6d6dd620
# endif
#endif
-#ifdef HAVE_QUOTA_SUPPORT
-
#ifdef NEED_QUOTA_DEFS
#ifndef QUOTABLOCK_BITS
#define QUOTABLOCK_BITS 10
#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS)
#endif
-/* XXX: these two structs should be in /usr/include/linux/quota.h */
-#ifndef HAVE_STRUCT_IF_DQINFO
-struct if_dqinfo {
+#ifndef QIF_BLIMITS
+#define QIF_BLIMITS 1
+#define QIF_SPACE 2
+#define QIF_ILIMITS 4
+#define QIF_INODES 8
+#define QIF_BTIME 16
+#define QIF_ITIME 32
+#define QIF_LIMITS (QIF_BLIMITS | QIF_ILIMITS)
+#define QIF_USAGE (QIF_SPACE | QIF_INODES)
+#define QIF_TIMES (QIF_BTIME | QIF_ITIME)
+#define QIF_ALL (QIF_LIMITS | QIF_USAGE | QIF_TIMES)
+#endif
+
+#endif /* !__KERNEL__ */
+
+/* XXX: same as if_dqinfo struct in kernel */
+struct obd_dqinfo {
__u64 dqi_bgrace;
__u64 dqi_igrace;
__u32 dqi_flags;
__u32 dqi_valid;
};
-#endif
-#ifndef HAVE_STRUCT_IF_DQBLK
-struct if_dqblk {
+/* XXX: same as if_dqblk struct in kernel, plus one padding */
+struct obd_dqblk {
__u64 dqb_bhardlimit;
__u64 dqb_bsoftlimit;
__u64 dqb_curspace;
__u64 dqb_btime;
__u64 dqb_itime;
__u32 dqb_valid;
+ __u32 padding;
};
-#endif
-
-#ifndef QIF_BLIMITS
-#define QIF_BLIMITS 1
-#define QIF_SPACE 2
-#define QIF_ILIMITS 4
-#define QIF_INODES 8
-#define QIF_BTIME 16
-#define QIF_ITIME 32
-#define QIF_LIMITS (QIF_BLIMITS | QIF_ILIMITS)
-#define QIF_USAGE (QIF_SPACE | QIF_INODES)
-#define QIF_TIMES (QIF_BTIME | QIF_ITIME)
-#define QIF_ALL (QIF_LIMITS | QIF_USAGE | QIF_TIMES)
-#endif
-
-#endif /* NEED_QUOTA_DEFS */
struct if_quotactl {
- int qc_cmd;
- int qc_type;
- int qc_id;
- int qc_stat;
- struct if_dqinfo qc_dqinfo;
- struct if_dqblk qc_dqblk;
- char obd_type[10];
+ __u32 qc_cmd;
+ __u32 qc_type;
+ __u32 qc_id;
+ __u32 qc_stat;
+ struct obd_dqinfo qc_dqinfo;
+ struct obd_dqblk qc_dqblk;
+ __u8 obd_type[16];
struct obd_uuid obd_uuid;
};
-#else
-
-struct if_quotactl {
-};
-
-#endif /* HAVE_QUOTA_SUPPORT */
-
#ifndef LPU64
/* x86_64 defines __u64 as "long" in userspace, but "long long" in the kernel */
#if defined(__x86_64__) && defined(__KERNEL__)
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
+CONFIG_QUOTA=y
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
CONFIG_AUTOFS4_FS=m
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
-+#ident "$Id: kallsyms-2.4-bgl.patch,v 1.1.20.1 2005/03/24 22:50:28 jacob Exp $"
++#ident "$Id: kallsyms-2.4-bgl.patch,v 1.1.20.2 2005/04/01 21:30:19 green Exp $"
+
+/*
+ This code uses the list of all kernel and module symbols to :-
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
-+#ident "$Id: kallsyms-2.4-bgl.patch,v 1.1.20.1 2005/03/24 22:50:28 jacob Exp $"
++#ident "$Id: kallsyms-2.4-bgl.patch,v 1.1.20.2 2005/04/01 21:30:19 green Exp $"
+
+#ifndef MODUTILS_KALLSYMS_H
+#define MODUTILS_KALLSYMS_H 1
default: all
-MODULES := ldiskfs #quotafmt_test
+MODULES := ldiskfs
+
+@QUOTA_TRUE@MODULES += quotafmt_test
# copy makefile over to not break patches
ext3_extra := $(wildcard @LINUX@/fs/ext3/Makefile)
ext3_sources := $(filter-out %.mod.c,$(wildcard @LINUX@/fs/ext3/*.c))
new_sources := iopen.c iopen.h extents.c mballoc.c proc.c
new_headers := ext3_extents.h
-#quotafmt_sources := lustre_quota_fmt.c
-#quotafmt_headers := lustre_quota_fmt.h
ldiskfs_patched_sources := $(notdir $(ext3_sources) $(ext3_headers)) $(new_sources) $(new_headers)
-ldiskfs_sources := $(ldiskfs_patched_sources) #$(quotafmt_sources) $(quotafmt_headers)
+ldiskfs_sources := $(ldiskfs_patched_sources)
+
+quotafmt_sources := lustre_quota_fmt.c
+quotafmt_headers := lustre_quota_fmt.h
+@QUOTA_TRUE@ldiskfs_sources += $(quotafmt_sources) $(quotafmt_headers)
ldiskfs-objs := $(filter %.o,$(ldiskfs_sources:.c=.o))
-#quotafmt-objs := quotafmt_test.o
+
+@QUOTA_TRUE@quotafmt-objs := quotafmt_test.o
EXTRA_PRE_CFLAGS := -I@LINUX@/fs -I@LUSTRE@ -I@LUSTRE@/ldiskfs
* linux/fs/quota_v2.c
*/
-
#ifndef EXPORT_SYMTAB
# define EXPORT_SYMTAB
#endif
#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 int check_quota_file(struct file *f, int type)
+{
+ 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;
+
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ size = f->f_op->read(f, (char *)&dqhead,
+ sizeof(struct lustre_disk_dqheader), &offset);
+ set_fs(fs);
+ if (size != sizeof(struct lustre_disk_dqheader))
+ return 0;
+ if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
+ le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
+ return 0;
+ return 1;
+}
+
/* Check whether given file is really lustre admin quotafile */
int lustre_check_quota_file(struct lustre_quota_info *lqi, int type)
{
- struct lustre_disk_dqheader dqhead;
- struct file *f = lqi->qi_files[type];
- 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;
-
- fs = get_fs();
- set_fs(KERNEL_DS);
- size = f->f_op->read(f, (char *)&dqhead, sizeof(struct lustre_disk_dqheader), &offset);
- set_fs(fs);
- if (size != sizeof(struct lustre_disk_dqheader))
- return 0;
- if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
- le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
- return 0;
- return 1;
+ struct file *f = lqi->qi_files[type];
+ return check_quota_file(f, type);
}
/* Read information header from quota file */
int lustre_read_quota_info(struct lustre_quota_info *lqi, int type)
{
- 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;
-
- fs = get_fs();
- set_fs(KERNEL_DS);
- size = f->f_op->read(f, (char *)&dinfo, sizeof(struct lustre_disk_dqinfo), &offset);
- set_fs(fs);
- if (size != sizeof(struct lustre_disk_dqinfo)) {
- printk(KERN_WARNING "Can't read info structure on device %s.\n",
- f->f_vfsmnt->mnt_sb->s_id);
- return -1;
- }
- info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
- info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
- info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
- info->dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
- info->dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
- info->dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
- return 0;
+ 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;
+
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ size = f->f_op->read(f, (char *)&dinfo,
+ sizeof(struct lustre_disk_dqinfo), &offset);
+ set_fs(fs);
+ if (size != sizeof(struct lustre_disk_dqinfo)) {
+ printk(KERN_WARNING "Can't read info structure on device %s.\n",
+ f->f_vfsmnt->mnt_sb->s_id);
+ return -1;
+ }
+ info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
+ info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
+ info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
+ info->dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
+ info->dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
+ info->dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
+ return 0;
}
/* Write information header to quota file */
int lustre_write_quota_info(struct lustre_quota_info *lqi, int type)
{
- 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;
-
- info->dqi_flags &= ~DQF_INFO_DIRTY;
- dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
- dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
- dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
- dinfo.dqi_blocks = cpu_to_le32(info->dqi_blocks);
- dinfo.dqi_free_blk = cpu_to_le32(info->dqi_free_blk);
- dinfo.dqi_free_entry = cpu_to_le32(info->dqi_free_entry);
- fs = get_fs();
- set_fs(KERNEL_DS);
- size = f->f_op->write(f, (char *)&dinfo, sizeof(struct lustre_disk_dqinfo), &offset);
- set_fs(fs);
- if (size != sizeof(struct lustre_disk_dqinfo)) {
- printk(KERN_WARNING "Can't write info structure on device %s.\n",
- f->f_vfsmnt->mnt_sb->s_id);
- return -1;
- }
- return 0;
+ 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;
+
+ info->dqi_flags &= ~DQF_INFO_DIRTY;
+ dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
+ dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
+ dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
+ dinfo.dqi_blocks = cpu_to_le32(info->dqi_blocks);
+ dinfo.dqi_free_blk = cpu_to_le32(info->dqi_free_blk);
+ dinfo.dqi_free_entry = cpu_to_le32(info->dqi_free_entry);
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ size = f->f_op->write(f, (char *)&dinfo,
+ sizeof(struct lustre_disk_dqinfo), &offset);
+ set_fs(fs);
+ if (size != sizeof(struct lustre_disk_dqinfo)) {
+ printk(KERN_WARNING
+ "Can't write info structure on device %s.\n",
+ f->f_vfsmnt->mnt_sb->s_id);
+ return -1;
+ }
+ return 0;
}
static void disk2memdqb(struct mem_dqblk *m, struct lustre_disk_dqblk *d)
{
- 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);
+ 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 lustre_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
+static void mem2diskdqb(struct lustre_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);
+ 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);
}
static dqbuf_t getdqbuf(void)
{
- dqbuf_t buf = kmalloc(LUSTRE_DQBLKSIZE, GFP_NOFS);
- if (!buf)
- printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n");
- return buf;
+ dqbuf_t buf = kmalloc(LUSTRE_DQBLKSIZE, GFP_NOFS);
+ if (!buf)
+ printk(KERN_WARNING
+ "VFS: Not enough memory for quota buffers.\n");
+ return buf;
}
static inline void freedqbuf(dqbuf_t buf)
{
- kfree(buf);
+ kfree(buf);
}
static ssize_t read_blk(struct file *filp, uint blk, dqbuf_t buf)
{
- mm_segment_t fs;
- ssize_t ret;
- loff_t offset = blk<<LUSTRE_DQBLKSIZE_BITS;
-
- memset(buf, 0, LUSTRE_DQBLKSIZE);
- fs = get_fs();
- set_fs(KERNEL_DS);
- ret = filp->f_op->read(filp, (char *)buf, LUSTRE_DQBLKSIZE, &offset);
- set_fs(fs);
- return ret;
+ mm_segment_t fs;
+ ssize_t ret;
+ loff_t offset = blk << LUSTRE_DQBLKSIZE_BITS;
+
+ memset(buf, 0, LUSTRE_DQBLKSIZE);
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = filp->f_op->read(filp, (char *)buf, LUSTRE_DQBLKSIZE, &offset);
+ set_fs(fs);
+ return ret;
}
static ssize_t write_blk(struct file *filp, uint blk, dqbuf_t buf)
{
- mm_segment_t fs;
- ssize_t ret;
- loff_t offset = blk<<LUSTRE_DQBLKSIZE_BITS;
+ mm_segment_t fs;
+ ssize_t ret;
+ loff_t offset = blk << LUSTRE_DQBLKSIZE_BITS;
- fs = get_fs();
- set_fs(KERNEL_DS);
- ret = filp->f_op->write(filp, (char *)buf, LUSTRE_DQBLKSIZE, &offset);
- set_fs(fs);
- return ret;
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ 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)
{
- set_bit(DQF_INFO_DIRTY_B, &info->dqi_flags);
+ 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)
{
- dqbuf_t buf = getdqbuf();
- struct lustre_disk_dqdbheader *dh = (struct lustre_disk_dqdbheader *)buf;
- int ret, blk;
-
- if (!buf)
- return -ENOMEM;
- if (info->dqi_free_blk) {
- blk = info->dqi_free_blk;
- if ((ret = read_blk(filp, blk, buf)) < 0)
- goto out_buf;
- 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... */
- goto out_buf;
- blk = info->dqi_blocks++;
- }
- lustre_mark_info_dirty(info);
- ret = blk;
+ dqbuf_t buf = getdqbuf();
+ struct lustre_disk_dqdbheader *dh =
+ (struct lustre_disk_dqdbheader *)buf;
+ int ret, blk;
+
+ if (!buf)
+ return -ENOMEM;
+ if (info->dqi_free_blk) {
+ blk = info->dqi_free_blk;
+ if ((ret = read_blk(filp, blk, buf)) < 0)
+ goto out_buf;
+ 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... */
+ goto out_buf;
+ blk = info->dqi_blocks++;
+ }
+ lustre_mark_info_dirty(info);
+ ret = blk;
out_buf:
- freedqbuf(buf);
- return ret;
+ freedqbuf(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)
+ dqbuf_t buf, uint blk)
{
- struct lustre_disk_dqdbheader *dh =(struct lustre_disk_dqdbheader *)buf;
- int err;
-
- dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk);
- dh->dqdh_prev_free = cpu_to_le32(0);
- dh->dqdh_entries = cpu_to_le16(0);
- info->dqi_free_blk = blk;
- lustre_mark_info_dirty(info);
- if ((err = write_blk(filp, blk, buf)) < 0)
- /* Some strange block. We had better leave it... */
- return err;
- return 0;
+ struct lustre_disk_dqdbheader *dh =
+ (struct lustre_disk_dqdbheader *)buf;
+ int err;
+
+ dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk);
+ dh->dqdh_prev_free = cpu_to_le32(0);
+ dh->dqdh_entries = cpu_to_le16(0);
+ info->dqi_free_blk = blk;
+ lustre_mark_info_dirty(info);
+ if ((err = write_blk(filp, blk, buf)) < 0)
+ /* Some strange block. We had better leave it... */
+ return err;
+ 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)
+static 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 = (struct lustre_disk_dqdbheader *)buf;
- uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free);
- int err;
-
- if (!tmpbuf)
- return -ENOMEM;
- if (nextblk) {
- if ((err = read_blk(filp, nextblk, tmpbuf)) < 0)
- goto out_buf;
- ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free;
- if ((err = write_blk(filp, nextblk, tmpbuf)) < 0)
- goto out_buf;
- }
- if (prevblk) {
- if ((err = read_blk(filp, prevblk, tmpbuf)) < 0)
- goto out_buf;
- ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free;
- if ((err = write_blk(filp, prevblk, tmpbuf)) < 0)
- goto out_buf;
- }
- else {
- info->dqi_free_entry = nextblk;
- lustre_mark_info_dirty(info);
- }
- 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 */
- printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk);
- return 0;
+ dqbuf_t tmpbuf = getdqbuf();
+ struct lustre_disk_dqdbheader *dh =
+ (struct lustre_disk_dqdbheader *)buf;
+ uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk =
+ le32_to_cpu(dh->dqdh_prev_free);
+ int err;
+
+ if (!tmpbuf)
+ return -ENOMEM;
+ if (nextblk) {
+ if ((err = read_blk(filp, nextblk, tmpbuf)) < 0)
+ goto out_buf;
+ ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_prev_free =
+ dh->dqdh_prev_free;
+ if ((err = write_blk(filp, nextblk, tmpbuf)) < 0)
+ goto out_buf;
+ }
+ if (prevblk) {
+ if ((err = read_blk(filp, prevblk, tmpbuf)) < 0)
+ goto out_buf;
+ ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_next_free =
+ dh->dqdh_next_free;
+ if ((err = write_blk(filp, prevblk, tmpbuf)) < 0)
+ goto out_buf;
+ } else {
+ info->dqi_free_entry = nextblk;
+ lustre_mark_info_dirty(info);
+ }
+ 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 */
+ printk(KERN_ERR
+ "VFS: Can't write block (%u) with free entries.\n", blk);
+ return 0;
out_buf:
- freedqbuf(tmpbuf);
- return err;
+ freedqbuf(tmpbuf);
+ 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)
+static int insert_free_dqentry(struct file *filp,
+ struct lustre_mem_dqinfo *info, dqbuf_t buf,
+ uint blk)
{
- dqbuf_t tmpbuf = getdqbuf();
- struct lustre_disk_dqdbheader *dh = (struct lustre_disk_dqdbheader *)buf;
- int err;
-
- if (!tmpbuf)
- return -ENOMEM;
- dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry);
- dh->dqdh_prev_free = cpu_to_le32(0);
- if ((err = write_blk(filp, blk, buf)) < 0)
- goto out_buf;
- if (info->dqi_free_entry) {
- if ((err = read_blk(filp, info->dqi_free_entry, tmpbuf)) < 0)
- goto out_buf;
- ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk);
- if ((err = write_blk(filp, info->dqi_free_entry, tmpbuf)) < 0)
- goto out_buf;
- }
- freedqbuf(tmpbuf);
- info->dqi_free_entry = blk;
- lustre_mark_info_dirty(info);
- return 0;
+ dqbuf_t tmpbuf = getdqbuf();
+ struct lustre_disk_dqdbheader *dh =
+ (struct lustre_disk_dqdbheader *)buf;
+ int err;
+
+ if (!tmpbuf)
+ return -ENOMEM;
+ dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry);
+ dh->dqdh_prev_free = cpu_to_le32(0);
+ if ((err = write_blk(filp, blk, buf)) < 0)
+ goto out_buf;
+ if (info->dqi_free_entry) {
+ if ((err = read_blk(filp, info->dqi_free_entry, tmpbuf)) < 0)
+ goto out_buf;
+ ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_prev_free =
+ cpu_to_le32(blk);
+ if ((err = write_blk(filp, info->dqi_free_entry, tmpbuf)) < 0)
+ goto out_buf;
+ }
+ freedqbuf(tmpbuf);
+ info->dqi_free_entry = blk;
+ lustre_mark_info_dirty(info);
+ return 0;
out_buf:
- freedqbuf(tmpbuf);
- return err;
+ freedqbuf(tmpbuf);
+ return err;
}
/* Find space for dquot */
static uint find_free_dqentry(struct lustre_dquot *dquot, int *err)
{
- struct lustre_quota_info *lqi = dquot->dq_info;
- struct file *filp = lqi->qi_files[dquot->dq_type];
- struct lustre_mem_dqinfo *info = &lqi->qi_info[dquot->dq_type];
- uint blk, i;
- struct lustre_disk_dqdbheader *dh;
- struct lustre_disk_dqblk *ddquot;
- struct lustre_disk_dqblk fakedquot;
- dqbuf_t buf;
-
- *err = 0;
- if (!(buf = getdqbuf())) {
- *err = -ENOMEM;
- return 0;
- }
- dh = (struct lustre_disk_dqdbheader *)buf;
- ddquot = GETENTRIES(buf);
- if (info->dqi_free_entry) {
- blk = info->dqi_free_entry;
- if ((*err = read_blk(filp, blk, buf)) < 0)
- goto out_buf;
- }
- else {
- blk = get_free_dqblk(filp, info);
- if ((int)blk < 0) {
- *err = blk;
- freedqbuf(buf);
- return 0;
- }
- memset(buf, 0, LUSTRE_DQBLKSIZE);
- info->dqi_free_entry = blk; /* This is enough as block is already zeroed and entry list is empty... */
- lustre_mark_info_dirty(info);
- }
- if (le16_to_cpu(dh->dqdh_entries)+1 >= LUSTRE_DQSTRINBLK) /* Block will be full? */
- if ((*err = remove_free_dqentry(filp, info, 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 lustre_disk_dqblk));
- /* Find free structure in block */
- for (i = 0; i < LUSTRE_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct lustre_disk_dqblk)); i++);
-
- if (i == LUSTRE_DQSTRINBLK) {
- printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
- *err = -EIO;
- goto out_buf;
- }
-
- if ((*err = write_blk(filp, blk, buf)) < 0) {
- printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
- goto out_buf;
- }
- dquot->dq_off = (blk<<LUSTRE_DQBLKSIZE_BITS)+sizeof(struct lustre_disk_dqdbheader)+i*sizeof(struct lustre_disk_dqblk);
- freedqbuf(buf);
- return blk;
+ struct lustre_quota_info *lqi = dquot->dq_info;
+ struct file *filp = lqi->qi_files[dquot->dq_type];
+ struct lustre_mem_dqinfo *info = &lqi->qi_info[dquot->dq_type];
+ uint blk, i;
+ struct lustre_disk_dqdbheader *dh;
+ struct lustre_disk_dqblk *ddquot;
+ struct lustre_disk_dqblk fakedquot;
+ dqbuf_t buf;
+
+ *err = 0;
+ if (!(buf = getdqbuf())) {
+ *err = -ENOMEM;
+ return 0;
+ }
+ dh = (struct lustre_disk_dqdbheader *)buf;
+ ddquot = GETENTRIES(buf);
+ if (info->dqi_free_entry) {
+ blk = info->dqi_free_entry;
+ if ((*err = read_blk(filp, blk, buf)) < 0)
+ goto out_buf;
+ } else {
+ blk = get_free_dqblk(filp, info);
+ if ((int)blk < 0) {
+ *err = blk;
+ freedqbuf(buf);
+ return 0;
+ }
+ memset(buf, 0, LUSTRE_DQBLKSIZE);
+ info->dqi_free_entry = blk; /* This is enough as block is already zeroed and entry list is empty... */
+ lustre_mark_info_dirty(info);
+ }
+ if (le16_to_cpu(dh->dqdh_entries) + 1 >= LUSTRE_DQSTRINBLK) /* Block will be full? */
+ if ((*err = remove_free_dqentry(filp, info, 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 lustre_disk_dqblk));
+ /* Find free structure in block */
+ for (i = 0; i < LUSTRE_DQSTRINBLK &&
+ memcmp(&fakedquot, ddquot + i, sizeof(fakedquot)); i++) ;
+
+ if (i == LUSTRE_DQSTRINBLK) {
+ printk(KERN_ERR
+ "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
+ *err = -EIO;
+ goto out_buf;
+ }
+
+ if ((*err = write_blk(filp, blk, buf)) < 0) {
+ printk(KERN_ERR
+ "VFS: find_free_dqentry(): Can't write quota data block %u.\n",
+ blk);
+ goto out_buf;
+ }
+ dquot->dq_off =
+ (blk << LUSTRE_DQBLKSIZE_BITS) +
+ sizeof(struct lustre_disk_dqdbheader) +
+ i * sizeof(struct lustre_disk_dqblk);
+ freedqbuf(buf);
+ return blk;
out_buf:
- freedqbuf(buf);
- return 0;
+ freedqbuf(buf);
+ return 0;
}
/* Insert reference to structure into the trie */
-static int do_insert_tree(struct lustre_dquot *dquot, uint *treeblk, int depth)
+static int do_insert_tree(struct lustre_dquot *dquot, uint * treeblk, int depth)
{
- struct lustre_quota_info *lqi = dquot->dq_info;
- struct file *filp = lqi->qi_files[dquot->dq_type];
- struct lustre_mem_dqinfo *info = &lqi->qi_info[dquot->dq_type];
- dqbuf_t buf;
- int ret = 0, newson = 0, newact = 0;
- u32 *ref;
- uint newblk;
-
- if (!(buf = getdqbuf()))
- return -ENOMEM;
- if (!*treeblk) {
- ret = get_free_dqblk(filp, info);
- if (ret < 0)
- goto out_buf;
- *treeblk = ret;
- memset(buf, 0, LUSTRE_DQBLKSIZE);
- newact = 1;
- }
- else {
- if ((ret = read_blk(filp, *treeblk, buf)) < 0) {
- printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk);
- goto out_buf;
- }
- }
- ref = (u32 *)buf;
- newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
- if (!newblk)
- newson = 1;
- if (depth == LUSTRE_DQTREEDEPTH-1) {
-
- if (newblk) {
- printk(KERN_ERR "VFS: Inserting already present quota entry (block %u).\n", ref[GETIDINDEX(dquot->dq_id, depth)]);
- ret = -EIO;
- goto out_buf;
- }
-
- newblk = find_free_dqentry(dquot, &ret);
- }
- else
- ret = do_insert_tree(dquot, &newblk, depth+1);
- if (newson && ret >= 0) {
- ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk);
- ret = write_blk(filp, *treeblk, buf);
- }
- else if (newact && ret < 0)
- put_free_dqblk(filp, info, buf, *treeblk);
+ struct lustre_quota_info *lqi = dquot->dq_info;
+ struct file *filp = lqi->qi_files[dquot->dq_type];
+ struct lustre_mem_dqinfo *info = &lqi->qi_info[dquot->dq_type];
+ dqbuf_t buf;
+ int ret = 0, newson = 0, newact = 0;
+ u32 *ref;
+ uint newblk;
+
+ if (!(buf = getdqbuf()))
+ return -ENOMEM;
+ if (!*treeblk) {
+ ret = get_free_dqblk(filp, info);
+ if (ret < 0)
+ goto out_buf;
+ *treeblk = ret;
+ memset(buf, 0, LUSTRE_DQBLKSIZE);
+ newact = 1;
+ } else {
+ if ((ret = read_blk(filp, *treeblk, buf)) < 0) {
+ printk(KERN_ERR
+ "VFS: Can't read tree quota block %u.\n",
+ *treeblk);
+ goto out_buf;
+ }
+ }
+ ref = (u32 *) buf;
+ newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
+ if (!newblk)
+ newson = 1;
+ if (depth == LUSTRE_DQTREEDEPTH - 1) {
+
+ if (newblk) {
+ printk(KERN_ERR
+ "VFS: Inserting already present quota entry (block %u).\n",
+ ref[GETIDINDEX(dquot->dq_id, depth)]);
+ ret = -EIO;
+ goto out_buf;
+ }
+
+ newblk = find_free_dqentry(dquot, &ret);
+ } else
+ ret = do_insert_tree(dquot, &newblk, depth + 1);
+ if (newson && ret >= 0) {
+ ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk);
+ ret = write_blk(filp, *treeblk, buf);
+ } else if (newact && ret < 0)
+ put_free_dqblk(filp, info, buf, *treeblk);
out_buf:
- freedqbuf(buf);
- return ret;
+ freedqbuf(buf);
+ return ret;
}
/* Wrapper for inserting quota structure into tree */
static inline int dq_insert_tree(struct lustre_dquot *dquot)
{
- int tmp = LUSTRE_DQTREEOFF;
- return do_insert_tree(dquot, &tmp, 0);
+ int tmp = LUSTRE_DQTREEOFF;
+ return do_insert_tree(dquot, &tmp, 0);
}
/*
*/
static int lustre_write_dquot(struct lustre_dquot *dquot)
{
- int type = dquot->dq_type;
- struct file *filp;
- mm_segment_t fs;
- loff_t offset;
- ssize_t ret;
- struct lustre_disk_dqblk ddquot, empty;
-
- if (!dquot->dq_off)
- if ((ret = dq_insert_tree(dquot)) < 0) {
- printk(KERN_ERR "VFS: Error %Zd occurred while creating quota.\n", ret);
- return ret;
- }
- filp = dquot->dq_info->qi_files[type];
- offset = dquot->dq_off;
- mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
- /* 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 lustre_disk_dqblk));
- if (!memcmp(&empty, &ddquot, sizeof(struct lustre_disk_dqblk)))
- ddquot.dqb_itime = cpu_to_le64(1);
- fs = get_fs();
- set_fs(KERNEL_DS);
- ret = filp->f_op->write(filp, (char *)&ddquot, sizeof(struct lustre_disk_dqblk), &offset);
- set_fs(fs);
- if (ret != sizeof(struct lustre_disk_dqblk)) {
- printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", filp->f_dentry->d_sb->s_id);
- if (ret >= 0)
- ret = -ENOSPC;
- }
- else
- ret = 0;
-
- return ret;
+ int type = dquot->dq_type;
+ struct file *filp;
+ mm_segment_t fs;
+ loff_t offset;
+ ssize_t ret;
+ struct lustre_disk_dqblk ddquot, empty;
+
+ if (!dquot->dq_off)
+ if ((ret = dq_insert_tree(dquot)) < 0) {
+ printk(KERN_ERR
+ "VFS: Error %Zd occurred while creating quota.\n",
+ ret);
+ return ret;
+ }
+ filp = dquot->dq_info->qi_files[type];
+ offset = dquot->dq_off;
+ mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
+ /* 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 lustre_disk_dqblk));
+ if (!memcmp(&empty, &ddquot, sizeof(struct lustre_disk_dqblk)))
+ ddquot.dqb_itime = cpu_to_le64(1);
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = filp->f_op->write(filp, (char *)&ddquot,
+ sizeof(struct lustre_disk_dqblk), &offset);
+ set_fs(fs);
+ if (ret != sizeof(struct lustre_disk_dqblk)) {
+ printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
+ filp->f_dentry->d_sb->s_id);
+ if (ret >= 0)
+ ret = -ENOSPC;
+ } else
+ ret = 0;
+
+ return ret;
}
/* Free dquot entry in data block */
static int free_dqentry(struct lustre_dquot *dquot, uint blk)
{
- struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
- struct lustre_mem_dqinfo *info = &dquot->dq_info->qi_info[dquot->dq_type];
- struct lustre_disk_dqdbheader *dh;
- dqbuf_t buf = getdqbuf();
- int ret = 0;
-
- if (!buf)
- return -ENOMEM;
- if (dquot->dq_off >> LUSTRE_DQBLKSIZE_BITS != blk) {
- printk(KERN_ERR "VFS: Quota structure has offset to other block (%u) than it should (%u).\n", blk, (uint)(dquot->dq_off >> LUSTRE_DQBLKSIZE_BITS));
- goto out_buf;
- }
- if ((ret = read_blk(filp, blk, buf)) < 0) {
- printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
- goto out_buf;
- }
- dh = (struct lustre_disk_dqdbheader *)buf;
- dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)-1);
- if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */
- if ((ret = remove_free_dqentry(filp, info, buf, blk)) < 0 ||
- (ret = put_free_dqblk(filp, info, buf, blk)) < 0) {
- printk(KERN_ERR "VFS: Can't move quota data block (%u) to free list.\n", blk);
- goto out_buf;
- }
- }
- else {
- memset(buf+(dquot->dq_off & ((1 << LUSTRE_DQBLKSIZE_BITS)-1)), 0, sizeof(struct lustre_disk_dqblk));
- if (le16_to_cpu(dh->dqdh_entries) == LUSTRE_DQSTRINBLK-1) {
- /* Insert will write block itself */
- if ((ret = insert_free_dqentry(filp, info, buf, blk)) < 0) {
- printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
- goto out_buf;
- }
- }
- else
- if ((ret = write_blk(filp, blk, buf)) < 0) {
- printk(KERN_ERR "VFS: Can't write quota data block %u\n", blk);
- goto out_buf;
- }
- }
- dquot->dq_off = 0; /* Quota is now unattached */
+ struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
+ struct lustre_mem_dqinfo *info =
+ &dquot->dq_info->qi_info[dquot->dq_type];
+ struct lustre_disk_dqdbheader *dh;
+ dqbuf_t buf = getdqbuf();
+ int ret = 0;
+
+ if (!buf)
+ return -ENOMEM;
+ if (dquot->dq_off >> LUSTRE_DQBLKSIZE_BITS != blk) {
+ printk(KERN_ERR
+ "VFS: Quota structure has offset to other block (%u) than it should (%u).\n",
+ blk, (uint) (dquot->dq_off >> LUSTRE_DQBLKSIZE_BITS));
+ goto out_buf;
+ }
+ if ((ret = read_blk(filp, blk, buf)) < 0) {
+ printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
+ goto out_buf;
+ }
+ dh = (struct lustre_disk_dqdbheader *)buf;
+ dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries) - 1);
+ if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */
+ if ((ret = remove_free_dqentry(filp, info, buf, blk)) < 0 ||
+ (ret = put_free_dqblk(filp, info, buf, blk)) < 0) {
+ printk(KERN_ERR
+ "VFS: Can't move quota data block (%u) to free list.\n",
+ blk);
+ goto out_buf;
+ }
+ } else {
+ memset(buf +
+ (dquot->dq_off & ((1 << LUSTRE_DQBLKSIZE_BITS) - 1)), 0,
+ sizeof(struct lustre_disk_dqblk));
+ if (le16_to_cpu(dh->dqdh_entries) == LUSTRE_DQSTRINBLK - 1) {
+ /* Insert will write block itself */
+ if ((ret =
+ insert_free_dqentry(filp, info, buf, blk)) < 0) {
+ printk(KERN_ERR
+ "VFS: Can't insert quota data block (%u) to free entry list.\n",
+ blk);
+ goto out_buf;
+ }
+ } else if ((ret = write_blk(filp, blk, buf)) < 0) {
+ printk(KERN_ERR
+ "VFS: Can't write quota data block %u\n", blk);
+ goto out_buf;
+ }
+ }
+ dquot->dq_off = 0; /* Quota is now unattached */
out_buf:
- freedqbuf(buf);
- return ret;
+ freedqbuf(buf);
+ return ret;
}
/* Remove reference to dquot from tree */
-static int remove_tree(struct lustre_dquot *dquot, uint *blk, int depth)
+static int remove_tree(struct lustre_dquot *dquot, uint * blk, int depth)
{
- struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
- struct lustre_mem_dqinfo *info = &dquot->dq_info->qi_info[dquot->dq_type];
- dqbuf_t buf = getdqbuf();
- int ret = 0;
- uint newblk;
- u32 *ref = (u32 *)buf;
-
- if (!buf)
- return -ENOMEM;
- if ((ret = read_blk(filp, *blk, buf)) < 0) {
- printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
- goto out_buf;
- }
- newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
- if (depth == LUSTRE_DQTREEDEPTH-1) {
- ret = free_dqentry(dquot, newblk);
- newblk = 0;
- }
- else
- ret = remove_tree(dquot, &newblk, depth+1);
- if (ret >= 0 && !newblk) {
- int i;
- ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
- for (i = 0; i < LUSTRE_DQBLKSIZE && !buf[i]; i++); /* Block got empty? */
- /* don't put the root block into free blk list! */
- if (i == LUSTRE_DQBLKSIZE && *blk != LUSTRE_DQTREEOFF) {
- put_free_dqblk(filp, info, buf, *blk);
- *blk = 0;
- }
- else
- if ((ret = write_blk(filp, *blk, buf)) < 0)
- printk(KERN_ERR "VFS: Can't write quota tree block %u.\n", *blk);
- }
+ struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
+ struct lustre_mem_dqinfo *info =
+ &dquot->dq_info->qi_info[dquot->dq_type];
+ dqbuf_t buf = getdqbuf();
+ int ret = 0;
+ uint newblk;
+ u32 *ref = (u32 *) buf;
+
+ if (!buf)
+ return -ENOMEM;
+ if ((ret = read_blk(filp, *blk, buf)) < 0) {
+ printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
+ goto out_buf;
+ }
+ newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
+ if (depth == LUSTRE_DQTREEDEPTH - 1) {
+ ret = free_dqentry(dquot, newblk);
+ newblk = 0;
+ } else
+ ret = remove_tree(dquot, &newblk, depth + 1);
+ if (ret >= 0 && !newblk) {
+ int i;
+ ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
+ for (i = 0; i < LUSTRE_DQBLKSIZE && !buf[i]; i++) ; /* Block got empty? */
+ /* don't put the root block into free blk list! */
+ if (i == LUSTRE_DQBLKSIZE && *blk != LUSTRE_DQTREEOFF) {
+ put_free_dqblk(filp, info, buf, *blk);
+ *blk = 0;
+ } else if ((ret = write_blk(filp, *blk, buf)) < 0)
+ printk(KERN_ERR
+ "VFS: Can't write quota tree block %u.\n", *blk);
+ }
out_buf:
- freedqbuf(buf);
- return ret;
+ freedqbuf(buf);
+ return ret;
}
/* Delete dquot from tree */
-#ifndef QFMT_NO_DELETE
static int lustre_delete_dquot(struct lustre_dquot *dquot)
{
- uint tmp = LUSTRE_DQTREEOFF;
+ uint tmp = LUSTRE_DQTREEOFF;
- if (!dquot->dq_off) /* Even not allocated? */
- return 0;
- return remove_tree(dquot, &tmp, 0);
+ if (!dquot->dq_off) /* Even not allocated? */
+ return 0;
+ return remove_tree(dquot, &tmp, 0);
}
-#endif
/* Find entry in block */
static loff_t find_block_dqentry(struct lustre_dquot *dquot, uint blk)
{
- struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
- dqbuf_t buf = getdqbuf();
- loff_t ret = 0;
- int i;
- struct lustre_disk_dqblk *ddquot = GETENTRIES(buf);
-
- if (!buf)
- return -ENOMEM;
- if ((ret = read_blk(filp, blk, buf)) < 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 < LUSTRE_DQSTRINBLK && le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
- else { /* ID 0 as a bit more complicated searching... */
- struct lustre_disk_dqblk fakedquot;
-
- memset(&fakedquot, 0, sizeof(struct lustre_disk_dqblk));
- for (i = 0; i < LUSTRE_DQSTRINBLK; i++)
- if (!le32_to_cpu(ddquot[i].dqb_id) && memcmp(&fakedquot, ddquot+i, sizeof(struct lustre_disk_dqblk)))
- break;
- }
- if (i == LUSTRE_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 << LUSTRE_DQBLKSIZE_BITS) + sizeof(struct lustre_disk_dqdbheader) + i * sizeof(struct lustre_disk_dqblk);
+ struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
+ dqbuf_t buf = getdqbuf();
+ loff_t ret = 0;
+ int i;
+ struct lustre_disk_dqblk *ddquot = GETENTRIES(buf);
+
+ if (!buf)
+ return -ENOMEM;
+ if ((ret = read_blk(filp, blk, buf)) < 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 < LUSTRE_DQSTRINBLK
+ && le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++) ;
+ else { /* ID 0 as a bit more complicated searching... */
+ struct lustre_disk_dqblk fakedquot;
+
+ memset(&fakedquot, 0, sizeof(struct lustre_disk_dqblk));
+ for (i = 0; i < LUSTRE_DQSTRINBLK; i++)
+ if (!le32_to_cpu(ddquot[i].dqb_id)
+ && memcmp(&fakedquot, ddquot + i,
+ sizeof(struct lustre_disk_dqblk)))
+ break;
+ }
+ if (i == LUSTRE_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 << LUSTRE_DQBLKSIZE_BITS) +
+ sizeof(struct lustre_disk_dqdbheader) +
+ i * sizeof(struct lustre_disk_dqblk);
out_buf:
- freedqbuf(buf);
- return ret;
+ freedqbuf(buf);
+ return ret;
}
/* Find entry for given id in the tree */
static loff_t find_tree_dqentry(struct lustre_dquot *dquot, uint blk, int depth)
{
- struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
- dqbuf_t buf = getdqbuf();
- loff_t ret = 0;
- u32 *ref = (u32 *)buf;
-
- if (!buf)
- return -ENOMEM;
- if ((ret = read_blk(filp, blk, buf)) < 0) {
- printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
- goto out_buf;
- }
- ret = 0;
- blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
- if (!blk) /* No reference? */
- goto out_buf;
- if (depth < LUSTRE_DQTREEDEPTH-1)
- ret = find_tree_dqentry(dquot, blk, depth+1);
- else
- ret = find_block_dqentry(dquot, blk);
+ struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
+ dqbuf_t buf = getdqbuf();
+ loff_t ret = 0;
+ u32 *ref = (u32 *) buf;
+
+ if (!buf)
+ return -ENOMEM;
+ if ((ret = read_blk(filp, blk, buf)) < 0) {
+ printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
+ goto out_buf;
+ }
+ ret = 0;
+ blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
+ if (!blk) /* No reference? */
+ goto out_buf;
+ if (depth < LUSTRE_DQTREEDEPTH - 1)
+ ret = find_tree_dqentry(dquot, blk, depth + 1);
+ else
+ ret = find_block_dqentry(dquot, blk);
out_buf:
- freedqbuf(buf);
- return ret;
+ freedqbuf(buf);
+ return ret;
}
/* Find entry for given id in the tree - wrapper function */
static inline loff_t find_dqentry(struct lustre_dquot *dquot)
{
- return find_tree_dqentry(dquot, LUSTRE_DQTREEOFF, 0);
+ return find_tree_dqentry(dquot, LUSTRE_DQTREEOFF, 0);
}
int lustre_read_dquot(struct lustre_dquot *dquot)
{
- int type = dquot->dq_type;
- struct file *filp;
- mm_segment_t fs;
- loff_t offset;
- struct lustre_disk_dqblk ddquot, empty;
- int ret = 0;
-
- filp = dquot->dq_info->qi_files[type];
-
- if (!filp || !dquot->dq_info) { /* Invalidated quota? */
- printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
- return -EIO;
- }
-
- offset = find_dqentry(dquot);
- if (offset <= 0) { /* Entry not present? */
- if (offset < 0)
- printk(KERN_ERR "VFS: Can't read quota structure for id %u.\n", dquot->dq_id);
- dquot->dq_off = 0;
- set_bit(DQ_FAKE_B, &dquot->dq_flags);
- memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
- ret = offset;
- }
- else {
- dquot->dq_off = offset;
- fs = get_fs();
- set_fs(KERNEL_DS);
- if ((ret = filp->f_op->read(filp, (char *)&ddquot, sizeof(struct lustre_disk_dqblk), &offset)) != sizeof(struct lustre_disk_dqblk)) {
- 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 lustre_disk_dqblk));
- }
- else {
- ret = 0;
- /* We need to escape back all-zero structure */
- memset(&empty, 0, sizeof(struct lustre_disk_dqblk));
- empty.dqb_itime = cpu_to_le64(1);
- if (!memcmp(&empty, &ddquot,
- sizeof(struct lustre_disk_dqblk)))
- ddquot.dqb_itime = 0;
- }
- set_fs(fs);
- disk2memdqb(&dquot->dq_dqb, &ddquot);
- }
-
- return ret;
+ int type = dquot->dq_type;
+ struct file *filp;
+ mm_segment_t fs;
+ loff_t offset;
+ struct lustre_disk_dqblk ddquot, empty;
+ int ret = 0;
+
+ filp = dquot->dq_info->qi_files[type];
+
+ if (!filp || !dquot->dq_info) { /* Invalidated quota? */
+ printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
+ return -EIO;
+ }
+
+ offset = find_dqentry(dquot);
+ if (offset <= 0) { /* Entry not present? */
+ if (offset < 0)
+ printk(KERN_ERR
+ "VFS: Can't read quota structure for id %u.\n",
+ dquot->dq_id);
+ dquot->dq_off = 0;
+ set_bit(DQ_FAKE_B, &dquot->dq_flags);
+ memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
+ ret = offset;
+ } else {
+ dquot->dq_off = offset;
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ if ((ret = filp->f_op->read(filp, (char *)&ddquot,
+ sizeof(struct lustre_disk_dqblk),
+ &offset)) !=
+ sizeof(struct lustre_disk_dqblk)) {
+ 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 lustre_disk_dqblk));
+ } else {
+ ret = 0;
+ /* We need to escape back all-zero structure */
+ memset(&empty, 0, sizeof(struct lustre_disk_dqblk));
+ empty.dqb_itime = cpu_to_le64(1);
+ if (!memcmp(&empty, &ddquot,
+ sizeof(struct lustre_disk_dqblk)))
+ ddquot.dqb_itime = 0;
+ }
+ set_fs(fs);
+ disk2memdqb(&dquot->dq_dqb, &ddquot);
+ }
+
+ return ret;
}
/* Commit changes of dquot to disk - it might also mean deleting it when quota became fake */
int lustre_commit_dquot(struct lustre_dquot *dquot)
{
- int rc = 0;
- /* always clear the flag so we don't loop on an IO error... */
- clear_bit(DQ_MOD_B, &dquot->dq_flags);
-
- /* The block/inode usage in admin quotafile isn't the real usage
- * over all cluster, so keep the fake dquot entry on disk is
- * meaningless, just remove it */
- if (test_bit(DQ_FAKE_B, &dquot->dq_flags))
- rc = lustre_delete_dquot(dquot);
- else
- rc = lustre_write_dquot(dquot);
- if (rc < 0)
- return rc;
-
- if (lustre_info_dirty(&dquot->dq_info->qi_info[dquot->dq_type]))
- rc = lustre_write_quota_info(dquot->dq_info, dquot->dq_type);
-
- return rc;
+ int rc = 0;
+ /* always clear the flag so we don't loop on an IO error... */
+ clear_bit(DQ_MOD_B, &dquot->dq_flags);
+
+ /* The block/inode usage in admin quotafile isn't the real usage
+ * over all cluster, so keep the fake dquot entry on disk is
+ * meaningless, just remove it */
+ if (test_bit(DQ_FAKE_B, &dquot->dq_flags))
+ rc = lustre_delete_dquot(dquot);
+ else
+ rc = lustre_write_dquot(dquot);
+
+ if (rc < 0)
+ return rc;
+
+ if (lustre_info_dirty(&dquot->dq_info->qi_info[dquot->dq_type]))
+ rc = lustre_write_quota_info(dquot->dq_info, dquot->dq_type);
+
+ return rc;
}
/* We need to export this function to initialize quotafile, because we haven't
* user level check utility */
int lustre_init_quota_info(struct lustre_quota_info *lqi, int type)
{
- struct lustre_mem_dqinfo *dqinfo = &lqi->qi_info[type];
- struct lustre_disk_dqheader dqhead;
- struct file *fp = lqi->qi_files[type];
- ssize_t size;
- loff_t offset = 0;
- int rc = 0;
- static const uint quota_magics[] = LUSTRE_INITQMAGICS;
- static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
-
- /* write quotafile header */
- dqhead.dqh_magic = cpu_to_le32(quota_magics[type]);
- dqhead.dqh_version = cpu_to_le32(quota_versions[type]);
- size = fp->f_op->write(fp, (char *)&dqhead,
- sizeof(struct lustre_disk_dqheader), &offset);
-
- if (size != sizeof(struct lustre_disk_dqheader)) {
- printk(KERN_ERR "error writing quoafile header (rc:%d)\n", rc);
- rc = size;
- }
- if (rc)
- return rc;
-
- /* write init quota info */
- memset(dqinfo, 0, sizeof(*dqinfo));
- dqinfo->dqi_bgrace = MAX_DQ_TIME;
- dqinfo->dqi_igrace = MAX_IQ_TIME;
- dqinfo->dqi_blocks = LUSTRE_DQTREEOFF + 1;
-
- return lustre_write_quota_info(lqi, type);
+ struct lustre_mem_dqinfo *dqinfo = &lqi->qi_info[type];
+ struct lustre_disk_dqheader dqhead;
+ struct file *fp = lqi->qi_files[type];
+ ssize_t size;
+ loff_t offset = 0;
+ int rc = 0;
+ static const uint quota_magics[] = LUSTRE_INITQMAGICS;
+ static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
+
+ /* write quotafile header */
+ dqhead.dqh_magic = cpu_to_le32(quota_magics[type]);
+ dqhead.dqh_version = cpu_to_le32(quota_versions[type]);
+ size = fp->f_op->write(fp, (char *)&dqhead,
+ sizeof(struct lustre_disk_dqheader), &offset);
+
+ if (size != sizeof(struct lustre_disk_dqheader)) {
+ printk(KERN_ERR "error writing quoafile header (rc:%d)\n", rc);
+ rc = size;
+ }
+ if (rc)
+ return rc;
+
+ /* write init quota info */
+ memset(dqinfo, 0, sizeof(*dqinfo));
+ dqinfo->dqi_bgrace = MAX_DQ_TIME;
+ dqinfo->dqi_igrace = MAX_IQ_TIME;
+ dqinfo->dqi_blocks = LUSTRE_DQTREEOFF + 1;
+
+ return lustre_write_quota_info(lqi, type);
+}
+
+struct dqblk {
+ struct list_head link;
+ uint blk;
+};
+
+static int walk_block_dqentry(struct file *filp, uint blk,
+ struct list_head *list)
+{
+ dqbuf_t buf = getdqbuf();
+ loff_t ret = 0;
+ struct lustre_disk_dqdbheader *dqhead =
+ (struct lustre_disk_dqdbheader *)buf;
+ struct dqblk *blk_item;
+ struct dqblk *pos;
+ struct list_head *tmp;
+
+ if (!buf)
+ return -ENOMEM;
+ if ((ret = read_blk(filp, blk, buf)) < 0) {
+ printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
+ goto out_buf;
+ }
+ ret = 0;
+
+ if (!le32_to_cpu(dqhead->dqdh_entries))
+ goto out_buf;
+
+ if (list_empty(list)) {
+ tmp = list;
+ goto done;
+ }
+
+ list_for_each_entry(pos, list, link) {
+ if (blk == pos->blk) /* we got this blk already */
+ goto out_buf;
+ if (blk > pos->blk)
+ continue;
+ break;
+ }
+ tmp = &pos->link;
+done:
+ blk_item = kmalloc(sizeof(*blk_item), GFP_NOFS);
+ if (!blk_item) {
+ ret = -ENOMEM;
+ goto out_buf;
+ }
+ blk_item->blk = blk;
+ INIT_LIST_HEAD(&blk_item->link);
+
+ list_add_tail(&blk_item->link, tmp);
+
+out_buf:
+ freedqbuf(buf);
+ return ret;
+}
+
+static int walk_tree_dqentry(struct file *filp, uint blk, int depth,
+ struct list_head *list)
+{
+ dqbuf_t buf = getdqbuf();
+ loff_t ret = 0;
+ int index;
+ u32 *ref = (u32 *) buf;
+
+ if (!buf)
+ return -ENOMEM;
+ if ((ret = read_blk(filp, blk, buf)) < 0) {
+ printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
+ goto out_buf;
+ }
+ ret = 0;
+
+ for (index = 0; index <= 0xff && !ret; index++) {
+ blk = le32_to_cpu(ref[index]);
+ if (!blk) /* No reference */
+ continue;
+
+ if (depth < LUSTRE_DQTREEDEPTH - 1)
+ ret = walk_tree_dqentry(filp, blk, depth + 1, list);
+ else
+ ret = walk_block_dqentry(filp, blk, list);
+ }
+out_buf:
+ freedqbuf(buf);
+ return ret;
+}
+
+/* Walk through the quota file (v2 format) to get all ids with quota limit */
+int lustre_get_qids(struct lustre_quota_info *lqi, int type,
+ struct list_head *list)
+{
+ struct file *fp = lqi->qi_files[type];
+ struct list_head blk_list;
+ struct dqblk *blk_item, *tmp;
+ dqbuf_t buf = NULL;
+ struct lustre_disk_dqblk *ddquot;
+ int rc;
+
+ if (!check_quota_file(fp, type)) {
+ printk(KERN_ERR "unknown quota file format!\n");
+ return -EINVAL;
+ }
+ if (!list_empty(list)) {
+ printk(KERN_ERR "not empty list\n");
+ return -EINVAL;
+ }
+
+ INIT_LIST_HEAD(&blk_list);
+ rc = walk_tree_dqentry(fp, LUSTRE_DQTREEOFF, 0, &blk_list);
+ if (rc) {
+ printk(KERN_ERR "walk through quota file failed!(%d)\n", rc);
+ goto out_free;
+ }
+ if (list_empty(&blk_list))
+ return 0;
+
+ buf = getdqbuf();
+ if (!buf)
+ return -ENOMEM;
+ ddquot = GETENTRIES(buf);
+
+ list_for_each_entry(blk_item, &blk_list, link) {
+ loff_t ret = 0;
+ int i;
+ struct lustre_disk_dqblk fakedquot;
+
+ memset(buf, 0, LUSTRE_DQBLKSIZE);
+ if ((ret = read_blk(fp, blk_item->blk, buf)) < 0) {
+ printk(KERN_ERR
+ "VFS: Can't read quota tree block %u.\n",
+ blk_item->blk);
+ rc = ret;
+ goto out_free;
+ }
+
+ memset(&fakedquot, 0, sizeof(struct lustre_disk_dqblk));
+ for (i = 0; i < LUSTRE_DQSTRINBLK; i++) {
+ struct dquot_id *dqid;
+ /* skip empty entry */
+ if (!memcmp
+ (&fakedquot, ddquot + i,
+ sizeof(struct lustre_disk_dqblk)))
+ continue;
+
+ dqid = kmalloc(sizeof(*dqid), GFP_NOFS);
+ if (!dqid) {
+ rc = -ENOMEM;
+ goto out_free;
+ }
+ dqid->di_id = le32_to_cpu(ddquot[i].dqb_id);
+ INIT_LIST_HEAD(&dqid->di_link);
+ list_add(&dqid->di_link, list);
+ }
+ }
+
+out_free:
+ list_for_each_entry_safe(blk_item, tmp, &blk_list, link) {
+ list_del_init(&blk_item->link);
+ kfree(blk_item);
+ }
+ if (buf)
+ freedqbuf(buf);
+ return rc;
}
EXPORT_SYMBOL(lustre_check_quota_file);
EXPORT_SYMBOL(lustre_read_dquot);
EXPORT_SYMBOL(lustre_commit_dquot);
EXPORT_SYMBOL(lustre_init_quota_info);
+EXPORT_SYMBOL(lustre_get_qids);
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
* Lustre administrative quota format
*
* from
* to blocks of these structures.
*/
struct lustre_disk_dqblk {
- __u32 dqb_id; /* id this quota applies to */
- __u32 dqb_ihardlimit; /* absolute limit on allocated inodes */
- __u32 dqb_isoftlimit; /* preferred inode limit */
- __u32 dqb_curinodes; /* current # allocated inodes */
- __u32 dqb_bhardlimit; /* absolute limit on disk space (in QUOTABLOCK_SIZE) */
- __u32 dqb_bsoftlimit; /* preferred limit on disk space (in QUOTABLOCK_SIZE) */
- __u64 dqb_curspace; /* current space occupied (in bytes) */
- __u64 dqb_btime; /* time limit for excessive disk use */
- __u64 dqb_itime; /* time limit for excessive inode use */
+ __u32 dqb_id; /* id this quota applies to */
+ __u32 dqb_ihardlimit; /* absolute limit on allocated inodes */
+ __u32 dqb_isoftlimit; /* preferred inode limit */
+ __u32 dqb_curinodes; /* current # allocated inodes */
+ __u32 dqb_bhardlimit; /* absolute limit on disk space (in QUOTABLOCK_SIZE) */
+ __u32 dqb_bsoftlimit; /* preferred limit on disk space (in QUOTABLOCK_SIZE) */
+ __u64 dqb_curspace; /* current space occupied (in bytes) */
+ __u64 dqb_btime; /* time limit for excessive disk use */
+ __u64 dqb_itime; /* time limit for excessive inode use */
};
/*
*/
/* First generic header */
struct lustre_disk_dqheader {
- __u32 dqh_magic; /* Magic number identifying file */
- __u32 dqh_version; /* File version */
+ __u32 dqh_magic; /* Magic number identifying file */
+ __u32 dqh_version; /* File version */
};
/* Header with type and version specific information */
struct lustre_disk_dqinfo {
- __u32 dqi_bgrace; /* Time before block soft limit becomes hard limit */
- __u32 dqi_igrace; /* Time before inode soft limit becomes hard limit */
- __u32 dqi_flags; /* Flags for quotafile (DQF_*) */
- __u32 dqi_blocks; /* Number of blocks in file */
- __u32 dqi_free_blk; /* Number of first free block in the list */
- __u32 dqi_free_entry; /* Number of block with at least one free entry */
+ __u32 dqi_bgrace; /* Time before block soft limit becomes hard limit */
+ __u32 dqi_igrace; /* Time before inode soft limit becomes hard limit */
+ __u32 dqi_flags; /* Flags for quotafile (DQF_*) */
+ __u32 dqi_blocks; /* Number of blocks in file */
+ __u32 dqi_free_blk; /* Number of first free block in the list */
+ __u32 dqi_free_entry; /* Number of block with at least one free entry */
};
/*
* there will be space for exactly 21 quota-entries in a block
*/
struct lustre_disk_dqdbheader {
- __u32 dqdh_next_free; /* Number of next block with free entry */
- __u32 dqdh_prev_free; /* Number of previous block with free entry */
- __u16 dqdh_entries; /* Number of valid entries in block */
- __u16 dqdh_pad1;
- __u32 dqdh_pad2;
+ __u32 dqdh_next_free; /* Number of next block with free entry */
+ __u32 dqdh_prev_free; /* Number of previous block with free entry */
+ __u16 dqdh_entries; /* Number of valid entries in block */
+ __u16 dqdh_pad1;
+ __u32 dqdh_pad2;
};
-#define LUSTRE_DQINFOOFF sizeof(struct lustre_disk_dqheader) /* Offset of info header in file */
+#define LUSTRE_DQINFOOFF sizeof(struct lustre_disk_dqheader) /* Offset of info header in file */
#define LUSTRE_DQBLKSIZE_BITS 10
-#define LUSTRE_DQBLKSIZE (1 << LUSTRE_DQBLKSIZE_BITS) /* Size of block with quota structures */
-#define LUSTRE_DQTREEOFF 1 /* Offset of tree in file in blocks */
-#define LUSTRE_DQTREEDEPTH 4 /* Depth of quota tree */
-#define LUSTRE_DQSTRINBLK ((LUSTRE_DQBLKSIZE - sizeof(struct lustre_disk_dqdbheader)) / sizeof(struct lustre_disk_dqblk)) /* Number of entries in one blocks */
-
+#define LUSTRE_DQBLKSIZE (1 << LUSTRE_DQBLKSIZE_BITS) /* Size of block with quota structures */
+#define LUSTRE_DQTREEOFF 1 /* Offset of tree in file in blocks */
+#define LUSTRE_DQTREEDEPTH 4 /* Depth of quota tree */
+#define LUSTRE_DQSTRINBLK ((LUSTRE_DQBLKSIZE - sizeof(struct lustre_disk_dqdbheader)) / sizeof(struct lustre_disk_dqblk)) /* Number of entries in one blocks */
-#endif /* lustre_quota_fmt.h */
+#endif /* lustre_quota_fmt.h */
#include "lustre_quota_fmt.h"
-char *test_quotafile[2] = {"usrquota_test", "grpquota_test"};
+char *test_quotafile[2] = { "usrquota_test", "grpquota_test" };
static int quotfmt_initialize(struct lustre_quota_info *lqi,
struct obd_device *tgt,
- struct lvfs_run_ctxt *saved)
+ struct lvfs_run_ctxt *saved)
{
- struct lustre_disk_dqheader dqhead;
- static const uint quota_magics[] = LUSTRE_INITQMAGICS;
- static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
- struct file *fp;
- struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
- size_t size;
- struct dentry *de;
- int i, rc = 0;
- ENTRY;
-
- push_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
-
- sema_init(&lqi->qi_sem, 1);
-
- for (i = 0; i < MAXQUOTAS; i++) {
- loff_t offset = 0;
- char *name = test_quotafile[i];
- int namelen = strlen(name);
-
- /* remove the stale test quotafile */
- down(&parent_inode->i_sem);
- de = lookup_one_len(name, tgt->obd_lvfs_ctxt.pwd, namelen);
- if (!IS_ERR(de) && de->d_inode)
- vfs_unlink(parent_inode, de);
- if (!IS_ERR(de))
- dput(de);
- up(&parent_inode->i_sem);
-
- /* create quota file */
- fp = filp_open(name, O_CREAT | O_EXCL, 0644);
- if (IS_ERR(fp)) {
- rc = PTR_ERR(fp);
- CERROR("error creating test quotafile %s (rc = %d)\n",
- name, rc);
- break;
- }
- lqi->qi_files[i] = fp;
-
- /* write quotafile header */
- dqhead.dqh_magic = cpu_to_le32(quota_magics[i]);
- dqhead.dqh_version = cpu_to_le32(quota_versions[i]);
- size = fp->f_op->write(fp, (char *)&dqhead,
- sizeof(struct lustre_disk_dqheader),
- &offset);
- if (size != sizeof(struct lustre_disk_dqheader)) {
- CERROR("error writing quoafile header %s (rc = %d)\n",
- name, rc);
- rc = size;
- break;
- }
- }
-
- RETURN(rc);
+ struct lustre_disk_dqheader dqhead;
+ static const uint quota_magics[] = LUSTRE_INITQMAGICS;
+ static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
+ struct file *fp;
+ struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
+ size_t size;
+ struct dentry *de;
+ int i, rc = 0;
+ ENTRY;
+
+ push_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
+
+ for (i = 0; i < MAXQUOTAS; i++) {
+ loff_t offset = 0;
+ char *name = test_quotafile[i];
+ int namelen = strlen(name);
+
+ /* remove the stale test quotafile */
+ down(&parent_inode->i_sem);
+ de = lookup_one_len(name, tgt->obd_lvfs_ctxt.pwd, namelen);
+ if (!IS_ERR(de) && de->d_inode)
+ vfs_unlink(parent_inode, de);
+ if (!IS_ERR(de))
+ dput(de);
+ up(&parent_inode->i_sem);
+
+ /* create quota file */
+ fp = filp_open(name, O_CREAT | O_EXCL, 0644);
+ if (IS_ERR(fp)) {
+ rc = PTR_ERR(fp);
+ CERROR("error creating test quotafile %s (rc = %d)\n",
+ name, rc);
+ break;
+ }
+ lqi->qi_files[i] = fp;
+
+ /* write quotafile header */
+ dqhead.dqh_magic = cpu_to_le32(quota_magics[i]);
+ dqhead.dqh_version = cpu_to_le32(quota_versions[i]);
+ size = fp->f_op->write(fp, (char *)&dqhead,
+ sizeof(struct lustre_disk_dqheader),
+ &offset);
+ if (size != sizeof(struct lustre_disk_dqheader)) {
+ CERROR("error writing quoafile header %s (rc = %d)\n",
+ name, rc);
+ rc = size;
+ break;
+ }
+ }
+
+ RETURN(rc);
}
static int quotfmt_finalize(struct lustre_quota_info *lqi,
- struct obd_device *tgt,
- struct lvfs_run_ctxt *saved)
+ struct obd_device *tgt, struct lvfs_run_ctxt *saved)
{
- struct dentry *de;
- struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
- int i, rc = 0;
- ENTRY;
-
- for (i = 0; i < MAXQUOTAS; i++) {
- char *name = test_quotafile[i];
- int namelen = strlen(name);
-
- if (lqi->qi_files[i] == NULL)
- continue;
-
- /* close quota file */
- filp_close(lqi->qi_files[i], 0);
-
- /* unlink quota file */
- down(&parent_inode->i_sem);
-
- de = lookup_one_len(name, tgt->obd_lvfs_ctxt.pwd, namelen);
- if (IS_ERR(de) || de->d_inode == NULL) {
- rc = IS_ERR(de) ? PTR_ERR(de) : -ENOENT;
- CERROR("error lookup quotafile %s (rc = %d)\n",
- name, rc);
- goto dput;
- }
-
- rc = vfs_unlink(parent_inode, de);
- if (rc)
- CERROR("error unlink quotafile %s (rc = %d)\n",
- name, rc);
-dput:
- if (!IS_ERR(de))
- dput(de);
- up(&parent_inode->i_sem);
- }
-
- pop_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
- RETURN(rc);
+ struct dentry *de;
+ struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
+ int i, rc = 0;
+ ENTRY;
+
+ for (i = 0; i < MAXQUOTAS; i++) {
+ char *name = test_quotafile[i];
+ int namelen = strlen(name);
+
+ if (lqi->qi_files[i] == NULL)
+ continue;
+
+ /* close quota file */
+ filp_close(lqi->qi_files[i], 0);
+
+ /* unlink quota file */
+ down(&parent_inode->i_sem);
+
+ de = lookup_one_len(name, tgt->obd_lvfs_ctxt.pwd, namelen);
+ if (IS_ERR(de) || de->d_inode == NULL) {
+ rc = IS_ERR(de) ? PTR_ERR(de) : -ENOENT;
+ CERROR("error lookup quotafile %s (rc = %d)\n",
+ name, rc);
+ goto dput;
+ }
+
+ rc = vfs_unlink(parent_inode, de);
+ if (rc)
+ CERROR("error unlink quotafile %s (rc = %d)\n",
+ name, rc);
+ dput:
+ if (!IS_ERR(de))
+ dput(de);
+ up(&parent_inode->i_sem);
+ }
+
+ pop_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
+ RETURN(rc);
}
static int quotfmt_test_1(struct lustre_quota_info *lqi)
{
- int i;
- ENTRY;
-
- for (i = 0; i < MAXQUOTAS; i++) {
- if (!lustre_check_quota_file(lqi, i))
- RETURN(-EINVAL);
- }
- RETURN(0);
+ int i;
+ ENTRY;
+
+ for (i = 0; i < MAXQUOTAS; i++) {
+ if (!lustre_check_quota_file(lqi, i))
+ RETURN(-EINVAL);
+ }
+ RETURN(0);
}
static void print_quota_info(struct lustre_quota_info *lqi)
{
#if 0
- struct lustre_mem_dqinfo *dqinfo;
- int i;
-
- for (i = 0; i < MAXQUOTAS; i++) {
- dqinfo = &lqi->qi_info[i];
- printk("%s quota info:\n", i == USRQUOTA ? "user " : "group");
- printk("dqi_bgrace(%u) dqi_igrace(%u) dqi_flags(%lu) dqi_blocks(%u) "
- "dqi_free_blk(%u) dqi_free_entry(%u)\n",
- dqinfo->dqi_bgrace, dqinfo->dqi_igrace, dqinfo->dqi_flags,
- dqinfo->dqi_blocks, dqinfo->dqi_free_blk,
- dqinfo->dqi_free_entry);
- }
+ struct lustre_mem_dqinfo *dqinfo;
+ int i;
+
+ for (i = 0; i < MAXQUOTAS; i++) {
+ dqinfo = &lqi->qi_info[i];
+ printk("%s quota info:\n", i == USRQUOTA ? "user " : "group");
+ printk
+ ("dqi_bgrace(%u) dqi_igrace(%u) dqi_flags(%lu) dqi_blocks(%u) "
+ "dqi_free_blk(%u) dqi_free_entry(%u)\n",
+ dqinfo->dqi_bgrace, dqinfo->dqi_igrace, dqinfo->dqi_flags,
+ dqinfo->dqi_blocks, dqinfo->dqi_free_blk,
+ dqinfo->dqi_free_entry);
+ }
#endif
}
static int quotfmt_test_2(struct lustre_quota_info *lqi)
{
- int i, rc = 0;
- ENTRY;
-
- for (i = 0; i < MAXQUOTAS; i++) {
- struct lustre_mem_dqinfo dqinfo;
-
- rc = lustre_init_quota_info(lqi, i);
- if (rc) {
- CERROR("init quotainfo(%d) failed! (rc:%d)\n", i, rc);
- break;
- }
- memcpy(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo));
-
- rc = lustre_read_quota_info(lqi, i);
- if (rc) {
- CERROR("read quotainfo(%d) failed! (rc:%d)\n", i, rc);
- break;
- }
-
- if(memcmp(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo))) {
- rc = -EINVAL;
- break;
- }
- }
- RETURN(rc);
+ int i, rc = 0;
+ ENTRY;
+
+ for (i = 0; i < MAXQUOTAS; i++) {
+ struct lustre_mem_dqinfo dqinfo;
+
+ rc = lustre_init_quota_info(lqi, i);
+ if (rc) {
+ CERROR("init quotainfo(%d) failed! (rc:%d)\n", i, rc);
+ break;
+ }
+ memcpy(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo));
+
+ rc = lustre_read_quota_info(lqi, i);
+ if (rc) {
+ CERROR("read quotainfo(%d) failed! (rc:%d)\n", i, rc);
+ break;
+ }
+
+ if (memcmp(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo))) {
+ rc = -EINVAL;
+ break;
+ }
+ }
+ RETURN(rc);
}
static struct lustre_dquot *get_rand_dquot(struct lustre_quota_info *lqi)
{
- struct lustre_dquot *dquot;
- unsigned int rand;
-
- OBD_ALLOC(dquot, sizeof(*dquot));
- if (dquot == NULL)
- return NULL;
-
- get_random_bytes(&rand, sizeof(rand));
- if (!rand)
- rand = 1000;
-
- dquot->dq_info = lqi;
- dquot->dq_id = rand % 1000 + 1;
- dquot->dq_type = rand % MAXQUOTAS;
-
- dquot->dq_dqb.dqb_bhardlimit = rand;
- dquot->dq_dqb.dqb_bsoftlimit = rand / 2;
- dquot->dq_dqb.dqb_curspace = rand / 3;
- dquot->dq_dqb.dqb_ihardlimit = rand;
- dquot->dq_dqb.dqb_isoftlimit = rand / 2;
- dquot->dq_dqb.dqb_curinodes = rand / 3;
- dquot->dq_dqb.dqb_btime = jiffies;
- dquot->dq_dqb.dqb_itime = jiffies;
-
- return dquot;
+ struct lustre_dquot *dquot;
+ unsigned int rand;
+
+ OBD_ALLOC(dquot, sizeof(*dquot));
+ if (dquot == NULL)
+ return NULL;
+
+ get_random_bytes(&rand, sizeof(rand));
+ if (!rand)
+ rand = 1000;
+
+ dquot->dq_info = lqi;
+ dquot->dq_id = rand % 1000 + 1;
+ dquot->dq_type = rand % MAXQUOTAS;
+
+ dquot->dq_dqb.dqb_bhardlimit = rand;
+ dquot->dq_dqb.dqb_bsoftlimit = rand / 2;
+ dquot->dq_dqb.dqb_curspace = rand / 3;
+ dquot->dq_dqb.dqb_ihardlimit = rand;
+ dquot->dq_dqb.dqb_isoftlimit = rand / 2;
+ dquot->dq_dqb.dqb_curinodes = rand / 3;
+ dquot->dq_dqb.dqb_btime = jiffies;
+ dquot->dq_dqb.dqb_itime = jiffies;
+
+ return dquot;
}
static void put_rand_dquot(struct lustre_dquot *dquot)
{
- OBD_FREE(dquot, sizeof(*dquot));
+ OBD_FREE(dquot, sizeof(*dquot));
}
static int write_check_dquot(struct lustre_quota_info *lqi)
{
- struct lustre_dquot *dquot;
- struct mem_dqblk dqblk;
- int rc = 0;
- ENTRY;
-
- dquot = get_rand_dquot(lqi);
- if (dquot == NULL)
- RETURN(-ENOMEM);
-
- /* for already exists entry, we set the dq_off by read_dquot */
- rc = lustre_read_dquot(dquot);
- if (rc) {
- CERROR("read dquot failed! (rc:%d)\n", rc);
- GOTO(out, rc);
- }
-
- /* for already exists entry, we rewrite it */
- rc = lustre_commit_dquot(dquot);
- if (rc) {
- CERROR("commit dquot failed! (rc:%d)\n", rc);
- GOTO(out, rc);
- }
- memcpy(&dqblk, &dquot->dq_dqb, sizeof(dqblk));
- memset(&dquot->dq_dqb, 0, sizeof(dqblk));
-
- rc = lustre_read_dquot(dquot);
- if (rc) {
- CERROR("read dquot failed! (rc:%d)\n", rc);
- GOTO(out, rc);
- }
-
- if (memcmp(&dqblk, &dquot->dq_dqb, sizeof(dqblk))) {
- rc = -EINVAL;
- GOTO(out, rc);
- }
-out:
- put_rand_dquot(dquot);
- RETURN(rc);
+ struct lustre_dquot *dquot;
+ struct mem_dqblk dqblk;
+ int rc = 0;
+ ENTRY;
+
+ dquot = get_rand_dquot(lqi);
+ if (dquot == NULL)
+ RETURN(-ENOMEM);
+
+ /* for already exists entry, we set the dq_off by read_dquot */
+ rc = lustre_read_dquot(dquot);
+ if (rc) {
+ CERROR("read dquot failed! (rc:%d)\n", rc);
+ GOTO(out, rc);
+ }
+
+ clear_bit(DQ_FAKE_B, &dquot->dq_flags);
+ /* for already exists entry, we rewrite it */
+ rc = lustre_commit_dquot(dquot);
+ if (rc) {
+ CERROR("commit dquot failed! (rc:%d)\n", rc);
+ GOTO(out, rc);
+ }
+ memcpy(&dqblk, &dquot->dq_dqb, sizeof(dqblk));
+ memset(&dquot->dq_dqb, 0, sizeof(dqblk));
+
+ rc = lustre_read_dquot(dquot);
+ if (rc) {
+ CERROR("read dquot failed! (rc:%d)\n", rc);
+ GOTO(out, rc);
+ }
+
+ if (memcmp(&dqblk, &dquot->dq_dqb, sizeof(dqblk))) {
+ rc = -EINVAL;
+ GOTO(out, rc);
+ }
+ out:
+ put_rand_dquot(dquot);
+ RETURN(rc);
}
static int quotfmt_test_3(struct lustre_quota_info *lqi)
{
- struct lustre_dquot *dquot;
- int i = 0, rc = 0;
- ENTRY;
-
- dquot = get_rand_dquot(lqi);
- if (dquot == NULL)
- RETURN(-ENOMEM);
-repeat:
- clear_bit(DQ_FAKE_B, &dquot->dq_flags);
- /* write a new dquot */
- rc = lustre_commit_dquot(dquot);
- if (rc) {
- CERROR("commit dquot failed! (rc:%d)\n", rc);
- GOTO(out, rc);
- }
- dquot->dq_off = 0;
- memset(&dquot->dq_dqb, 0, sizeof(dquot->dq_dqb));
-
- /* check if this dquot is on disk now */
- rc = lustre_read_dquot(dquot);
- if (rc) {
- CERROR("read dquot failed! (rc:%d)\n", rc);
- GOTO(out, rc);
- }
- if (!dquot->dq_off || test_bit(DQ_FAKE_B, &dquot->dq_flags)) {
- CERROR("the dquot isn't committed\n");
- GOTO(out, rc = -EINVAL);
- }
-
- /* remove this dquot */
- set_bit(DQ_FAKE_B, &dquot->dq_flags);
- dquot->dq_dqb.dqb_curspace = 0;
- dquot->dq_dqb.dqb_curinodes = 0;
- rc = lustre_commit_dquot(dquot);
- if (rc) {
- CERROR("remove dquot failed! (rc:%d)\n", rc);
- GOTO(out, rc);
- }
-
- /* check if the dquot is really removed */
- clear_bit(DQ_FAKE_B, &dquot->dq_flags);
- dquot->dq_off = 0;
- rc = lustre_read_dquot(dquot);
- if (rc) {
- CERROR("read dquot failed! (rc:%d)\n", rc);
- GOTO(out, rc);
- }
- if (!test_bit(DQ_FAKE_B, &dquot->dq_flags) || dquot->dq_off) {
- CERROR("the dquot isn't removed!\n");
- GOTO(out, rc = -EINVAL);
- }
-
- /* check if this dquot can be write again */
- if (++i < 2)
- goto repeat;
+ struct lustre_dquot *dquot;
+ int i = 0, rc = 0;
+ ENTRY;
+
+ dquot = get_rand_dquot(lqi);
+ if (dquot == NULL)
+ RETURN(-ENOMEM);
+ repeat:
+ clear_bit(DQ_FAKE_B, &dquot->dq_flags);
+ /* write a new dquot */
+ rc = lustre_commit_dquot(dquot);
+ if (rc) {
+ CERROR("commit dquot failed! (rc:%d)\n", rc);
+ GOTO(out, rc);
+ }
+ dquot->dq_off = 0;
+ memset(&dquot->dq_dqb, 0, sizeof(dquot->dq_dqb));
+
+ /* check if this dquot is on disk now */
+ rc = lustre_read_dquot(dquot);
+ if (rc) {
+ CERROR("read dquot failed! (rc:%d)\n", rc);
+ GOTO(out, rc);
+ }
+ if (!dquot->dq_off || test_bit(DQ_FAKE_B, &dquot->dq_flags)) {
+ CERROR("the dquot isn't committed\n");
+ GOTO(out, rc = -EINVAL);
+ }
+
+ /* remove this dquot */
+ set_bit(DQ_FAKE_B, &dquot->dq_flags);
+ dquot->dq_dqb.dqb_curspace = 0;
+ dquot->dq_dqb.dqb_curinodes = 0;
+ rc = lustre_commit_dquot(dquot);
+ if (rc) {
+ CERROR("remove dquot failed! (rc:%d)\n", rc);
+ GOTO(out, rc);
+ }
+
+ /* check if the dquot is really removed */
+ clear_bit(DQ_FAKE_B, &dquot->dq_flags);
+ dquot->dq_off = 0;
+ rc = lustre_read_dquot(dquot);
+ if (rc) {
+ CERROR("read dquot failed! (rc:%d)\n", rc);
+ GOTO(out, rc);
+ }
+ if (!test_bit(DQ_FAKE_B, &dquot->dq_flags) || dquot->dq_off) {
+ CERROR("the dquot isn't removed!\n");
+ GOTO(out, rc = -EINVAL);
+ }
+
+ /* check if this dquot can be write again */
+ if (++i < 2)
+ goto repeat;
print_quota_info(lqi);
-out:
- put_rand_dquot(dquot);
- RETURN(rc);
+ out:
+ put_rand_dquot(dquot);
+ RETURN(rc);
}
static int quotfmt_test_4(struct lustre_quota_info *lqi)
{
- int i, rc = 0;
- ENTRY;
-
- for (i = 0; i < 30000; i++) {
- rc = write_check_dquot(lqi);
- if (rc) {
- CERROR("write/check dquot failed at %d! (rc:%d)\n",
- i, rc);
- break;
- }
- }
- print_quota_info(lqi);
- RETURN(rc);
+ int i, rc = 0;
+ ENTRY;
+
+ for (i = 0; i < 30000; i++) {
+ rc = write_check_dquot(lqi);
+ if (rc) {
+ CERROR("write/check dquot failed at %d! (rc:%d)\n",
+ i, rc);
+ break;
+ }
+ }
+ print_quota_info(lqi);
+ RETURN(rc);
+}
+
+static int quotfmt_test_5(struct lustre_quota_info *lqi)
+{
+ int i, rc = 0;
+
+ for (i = USRQUOTA; i < MAXQUOTAS && !rc; i++) {
+ struct list_head list;
+ struct dquot_id *dqid, *tmp;
+
+ INIT_LIST_HEAD(&list);
+ rc = lustre_get_qids(lqi, i, &list);
+ if (rc) {
+ CERROR("%s get all %ss (rc:%d):\n",
+ rc ? "error" : "success",
+ i == USRQUOTA ? "uid" : "gid", rc);
+ }
+ list_for_each_entry_safe(dqid, tmp, &list, di_link) {
+ list_del_init(&dqid->di_link);
+ if (rc == 0)
+ printk("%d ", dqid->di_id);
+ kfree(dqid);
+ }
+ printk("\n");
+ }
+ return rc;
}
static int quotfmt_run_tests(struct obd_device *obd, struct obd_device *tgt)
{
struct lvfs_run_ctxt saved;
- struct lustre_quota_info *lqi = NULL;
- int rc = 0;
- ENTRY;
-
- OBD_ALLOC(lqi, sizeof(*lqi));
- if (lqi == NULL) {
- CERROR("not enough memory\n");
- RETURN(-ENOMEM);
- }
-
- CWARN("=== Initialize quotafile test\n");
- rc = quotfmt_initialize(lqi, tgt, &saved);
- if (rc)
- GOTO(out, rc);
-
- CWARN("=== test 1: check quota header\n");
- rc = quotfmt_test_1(lqi);
- if (rc) {
- CERROR("check quota header failed! (rc:%d)\n", rc);
- GOTO(out, rc);
- }
-
- CWARN("=== test 2: write/read quota info\n");
- rc = quotfmt_test_2(lqi);
- if (rc) {
- CERROR("write/read quota info failed! (rc:%d)\n", rc);
- GOTO(out, rc);
- }
-
- CWARN("=== test 3: write/remove dquot\n");
- rc = quotfmt_test_3(lqi);
- if (rc) {
- CERROR("write/remove dquot failed! (rc:%d)\n", rc);
- GOTO(out, rc);
- }
-
- CWARN("=== test 4: write/read 30000 dquot\n");
- rc = quotfmt_test_4(lqi);
- if (rc) {
- CERROR("write/read 30000 dquot failed\n");
- GOTO(out, rc);
- }
-out:
- CWARN("=== Finalize quotafile test\n");
- rc = quotfmt_finalize(lqi, tgt, &saved);
- OBD_FREE(lqi, sizeof(*lqi));
- RETURN(rc);
+ struct lustre_quota_info *lqi = NULL;
+ int rc = 0;
+ ENTRY;
+
+ OBD_ALLOC(lqi, sizeof(*lqi));
+ if (lqi == NULL) {
+ CERROR("not enough memory\n");
+ RETURN(-ENOMEM);
+ }
+
+ CWARN("=== Initialize quotafile test\n");
+ rc = quotfmt_initialize(lqi, tgt, &saved);
+ if (rc)
+ GOTO(out, rc);
+
+ CWARN("=== test 1: check quota header\n");
+ rc = quotfmt_test_1(lqi);
+ if (rc) {
+ CERROR("check quota header failed! (rc:%d)\n", rc);
+ GOTO(out, rc);
+ }
+
+ CWARN("=== test 2: write/read quota info\n");
+ rc = quotfmt_test_2(lqi);
+ if (rc) {
+ CERROR("write/read quota info failed! (rc:%d)\n", rc);
+ GOTO(out, rc);
+ }
+
+ CWARN("=== test 3: write/remove dquot\n");
+ rc = quotfmt_test_3(lqi);
+ if (rc) {
+ CERROR("write/remove dquot failed! (rc:%d)\n", rc);
+ GOTO(out, rc);
+ }
+
+ CWARN("=== test 4: write/read 30000 dquot\n");
+ rc = quotfmt_test_4(lqi);
+ if (rc) {
+ CERROR("write/read 30000 dquot failed\n");
+ GOTO(out, rc);
+ }
+
+ CWARN("=== test 5: walk through quota file to get all ids\n");
+ rc = quotfmt_test_5(lqi);
+ if (rc) {
+ CERROR("walk through quota file failed\n");
+ GOTO(out, rc);
+ }
+ out:
+ CWARN("=== Finalize quotafile test\n");
+ rc = quotfmt_finalize(lqi, tgt, &saved);
+ OBD_FREE(lqi, sizeof(*lqi));
+ RETURN(rc);
}
static int quotfmt_test_cleanup(struct obd_device *obd)
{
- ENTRY;
+ ENTRY;
lprocfs_obd_cleanup(obd);
RETURN(0);
}
{
struct lprocfs_static_vars lvars;
struct lustre_cfg *lcfg = buf;
- struct obd_device *tgt;
+ struct obd_device *tgt;
int rc;
ENTRY;
}
static struct obd_ops quotfmt_obd_ops = {
- .o_owner = THIS_MODULE,
- .o_setup = quotfmt_test_setup,
- .o_cleanup = quotfmt_test_cleanup,
+ .o_owner = THIS_MODULE,
+ .o_setup = quotfmt_test_setup,
+ .o_cleanup = quotfmt_test_cleanup,
};
#ifdef LPROCFS
static struct lprocfs_vars lprocfs_obd_vars[] = { {0} };
static struct lprocfs_vars lprocfs_module_vars[] = { {0} };
+
LPROCFS_INIT_VARS(quotfmt_test, lprocfs_module_vars, lprocfs_obd_vars)
#endif
-
static int __init quotfmt_test_init(void)
{
struct lprocfs_static_vars lvars;
lprocfs_init_vars(quotfmt_test, &lvars);
return class_register_type("fmt_obd_ops, lvars.module_vars,
- "quotfmt_test");
+ "quotfmt_test");
}
static void __exit quotfmt_test_exit(void)
}
}
- spin_lock_init(&cli->cl_qchk_lock);
- cli->cl_qchk_stat = CL_NO_QUOTACHECK;
+ cli->cl_qchk_stat = CL_NOT_QUOTACHECKED;
RETURN(rc);
obd->obd_replayed_requests++;
reset_recovery_timer(obd);
/* bug 1580: decide how to properly sync() in recovery */
- //mds_fsync_super(mds->mds_sb);
+ //mds_fsync_super(obd->u.obt.obt_sb);
class_export_put(req->rq_export);
if (req->rq_reply_state != NULL) {
ptlrpc_rs_decref(req->rq_reply_state);
}
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 = lustre_swab_reqbuf(req, 0, sizeof(*oqctl),
+ lustre_swab_obd_quotactl);
+
+ cli->cl_qchk_stat = oqctl->qc_stat;
+
+ return 0;
+}
+
+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 lustre_quota_ctxt *qctxt;
+ struct qunit_data *qdata, *rep;
+ int rc = 0, repsize = sizeof(struct qunit_data);
+ ENTRY;
+
+ rc = lustre_pack_reply(req, 1, &repsize, NULL);
+ if (rc) {
+ CERROR("packing reply failed!: rc = %d\n", rc);
+ RETURN(rc);
+ }
+ rep = lustre_msg_buf(req->rq_repmsg, 0, sizeof(*rep));
+ LASSERT(rep);
+
+ qdata = lustre_swab_reqbuf(req, 0, sizeof(*qdata), lustre_swab_qdata);
+ if (qdata == NULL) {
+ CERROR("unpacking request buffer failed!");
+ RETURN(-EPROTO);
+ }
+
+ /* we use the observer */
+ LASSERT(obd->obd_observer && obd->obd_observer->obd_observer);
+ master_obd = obd->obd_observer->obd_observer;
+ qctxt = &master_obd->u.obt.obt_qctxt;
+
+ LASSERT(qctxt->lqc_handler);
+ rc = qctxt->lqc_handler(master_obd, qdata, req->rq_reqmsg->opc);
+ if (rc && rc != -EDQUOT)
+ CDEBUG(rc == -EBUSY ? D_QUOTA : D_ERROR,
+ "dqacq failed! (rc:%d)\n", rc);
+
+ /* the qd_count might be changed in lqc_handler */
+ memcpy(rep, qdata, sizeof(*rep));
+ req->rq_status = rc;
+ rc = ptlrpc_reply(req);
+
+ RETURN(rc);
+#else
+ return 0;
+#endif /* !__KERNEL__ */
+}
+#endif /* HAVE_QUOTA_SUPPORT */
$(top_builddir)/lustre/obdclass/liblustreclass.a \
$(top_builddir)/lustre/lvfs/liblvfs.a
+if QUOTA
+QUOTA_LIBS = $(top_builddir)/lustre/quota/libquota.a
+endif
+
LND_LIBS =
if BUILD_USOCKLND
LND_LIBS += $(top_builddir)/lnet/ulnds/socklnd/libsocklnd.a
liblustre_a_SOURCES = llite_lib.c super.c namei.c rw.c file.c dir.c \
llite_lib.h
-liblustre.a : $(LUSTRE_LIBS) $(LND_LIBS) $(LNET_LIBS) $(SYSIO_LIBS)
- sh $(srcdir)/genlib.sh "$(SYSIO)" "$(LIBS)" "$(LND_LIBS)" "$(PTHREAD_LIBS)"
+liblustre.a : $(LUSTRE_LIBS) $(LND_LIBS) $(LNET_LIBS) $(SYSIO_LIBS) $(QUOTA_LIBS)
+ sh $(srcdir)/genlib.sh "$(SYSIO)" "$(LIBS)" "$(LND_LIBS)" "$(PTHREAD_LIBS)" "$(QUOTA_LIBS)"
EXTRA_DIST = genlib.sh
LIBS=$2
LND_LIBS=$3
PTHREAD_LIBS=$4
+QUOTA_LIBS=$5
if [ ! -f $SYSIO/lib/libsysio.a ]; then
echo "ERROR: $SYSIO/lib/libsysio.a dosen't exist"
fi
build_obj_list ../../lnet/lnet liblnet.a
+if [ "x$QUOTA_LIBS" != "x" ]; then
+ build_obj_list ../quota libquota.a
+fi
+
# create static lib lsupport
rm -f $CWD/liblsupport.a
$AR -cru $CWD/liblsupport.a $ALL_OBJS
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, "lov_quota_interface"))
+ return &lov_quota_interface;
+#endif
else
return NULL;
}
RETURN(rc);
}
-#define Q_CONV(tgt, src, member) (tgt)->member = (src)->member
-
-#define QCTLCONV(tgt, src) \
-do { \
- Q_CONV(tgt, src, qc_cmd); \
- Q_CONV(tgt, src, qc_type); \
- Q_CONV(tgt, src, qc_id); \
- Q_CONV(tgt, src, qc_stat); \
- Q_CONV(tgt, src, qc_dqinfo.dqi_bgrace); \
- Q_CONV(tgt, src, qc_dqinfo.dqi_igrace); \
- Q_CONV(tgt, src, qc_dqinfo.dqi_flags); \
- Q_CONV(tgt, src, qc_dqblk.dqb_ihardlimit); \
- Q_CONV(tgt, src, qc_dqblk.dqb_isoftlimit); \
- Q_CONV(tgt, src, qc_dqblk.dqb_curinodes); \
- Q_CONV(tgt, src, qc_dqblk.dqb_bhardlimit); \
- Q_CONV(tgt, src, qc_dqblk.dqb_bsoftlimit); \
- Q_CONV(tgt, src, qc_dqblk.dqb_curspace); \
- Q_CONV(tgt, src, qc_dqblk.dqb_btime); \
- Q_CONV(tgt, src, qc_dqblk.dqb_itime); \
+#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)
static int ll_dir_ioctl(struct inode *inode, struct file *file,
RETURN(rc);
}
case OBD_IOC_QUOTACHECK: {
- struct obd_quotactl oqctl = { 0, };
+ struct obd_quotactl *oqctl;
int rc, error = 0;
if (!capable(CAP_SYS_ADMIN))
RETURN(-EPERM);
- oqctl.qc_type = arg;
- rc = obd_quotacheck(sbi->ll_mdc_exp, &oqctl);
+ OBD_ALLOC_PTR(oqctl);
+ if (!oqctl)
+ RETURN(-ENOMEM);
+ oqctl->qc_type = arg;
+ rc = obd_quotacheck(sbi->ll_mdc_exp, oqctl);
if (rc < 0) {
CDEBUG(D_INFO, "mdc_quotacheck failed: rc %d\n", rc);
error = rc;
}
- rc = obd_quotacheck(sbi->ll_osc_exp, &oqctl);
+ rc = obd_quotacheck(sbi->ll_osc_exp, oqctl);
if (rc < 0)
CDEBUG(D_INFO, "osc_quotacheck failed: rc %d\n", rc);
- if (error)
- rc = error;
- return rc;
+ OBD_FREE_PTR(oqctl);
+ return error ?: rc;
}
case OBD_IOC_POLL_QUOTACHECK: {
- struct if_quotacheck check;
+ struct if_quotacheck *check;
int rc;
if (!capable(CAP_SYS_ADMIN))
RETURN(-EPERM);
- rc = obd_iocontrol(cmd, sbi->ll_mdc_exp, 0, (void *)&check,
+ OBD_ALLOC_PTR(check);
+ if (!check)
+ RETURN(-ENOMEM);
+
+ rc = obd_iocontrol(cmd, sbi->ll_mdc_exp, 0, (void *)check,
NULL);
- if (check.stat == -ENODATA)
- rc = check.stat;
if (rc) {
- CDEBUG(D_QUOTA, "mdc ioctl %d failed: rc %d\n",
- cmd, check.stat);
- if (copy_to_user((void *)arg, &check, sizeof(check)))
- RETURN(-EFAULT);
- RETURN(rc);
+ CDEBUG(D_QUOTA, "mdc ioctl %d failed: %d\n", cmd, rc);
+ if (copy_to_user((void *)arg, check, sizeof(*check)))
+ rc = -EFAULT;
+ GOTO(out_poll, rc);
}
- rc = obd_iocontrol(cmd, sbi->ll_osc_exp, 0, (void *)&check,
+ rc = obd_iocontrol(cmd, sbi->ll_osc_exp, 0, (void *)check,
NULL);
- if (check.stat == -ENODATA)
- rc = check.stat;
if (rc) {
- CDEBUG(D_QUOTA, "osc ioctl %d failed: rc %d\n",
- cmd, rc);
- if (copy_to_user((void *)arg, &check, sizeof(check)))
- RETURN(-EFAULT);
- RETURN(rc);
+ CDEBUG(D_QUOTA, "osc ioctl %d failed: %d\n", cmd, rc);
+ if (copy_to_user((void *)arg, check, sizeof(*check)))
+ rc = -EFAULT;
+ GOTO(out_poll, rc);
}
-
- RETURN(0);
+ out_poll:
+ OBD_FREE_PTR(check);
+ RETURN(rc);
}
#if HAVE_QUOTA_SUPPORT
case OBD_IOC_QUOTACTL: {
- struct if_quotactl qctl;
- struct obd_quotactl oqctl;
+ struct if_quotactl *qctl;
+ struct obd_quotactl *oqctl;
- int cmd, type, id, rc = 0, error = 0;
+ int cmd, type, id, rc = 0;
- if (copy_from_user(&qctl, (void *)arg, sizeof(qctl)))
- RETURN(-EFAULT);
+ OBD_ALLOC_PTR(qctl);
+ if (!qctl)
+ RETURN(-ENOMEM);
- cmd = qctl.qc_cmd;
- type = qctl.qc_type;
- id = qctl.qc_id;
+ 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;
switch (cmd) {
case Q_QUOTAON:
case Q_QUOTAOFF:
case Q_SETQUOTA:
case Q_SETINFO:
if (!capable(CAP_SYS_ADMIN))
- RETURN(-EPERM);
+ GOTO(out_quotactl, rc = -EPERM);
break;
case Q_GETQUOTA:
if (((type == USRQUOTA && current->euid != id) ||
(type == GRPQUOTA && !in_egroup_p(id))) &&
!capable(CAP_SYS_ADMIN))
- RETURN(-EPERM);
+ 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_mdc_exp->exp_obd->u.cli.
+ cl_import->imp_target_uuid;
break;
case Q_GETINFO:
break;
default:
- RETURN(-EINVAL);
+ CERROR("unsupported quotactl op: %#x\n", cmd);
+ GOTO(out_quotactl, -ENOTTY);
}
- QCTLCONV(&oqctl, &qctl);
+ QCTL_COPY(oqctl, qctl);
- if (qctl.obd_uuid.uuid[0]) {
+ if (qctl->obd_uuid.uuid[0]) {
struct obd_device *obd;
- struct obd_uuid *uuid = &qctl.obd_uuid;
-
- if (cmd == Q_GETINFO)
- oqctl.qc_cmd = Q_GETOINFO;
- else if (cmd == Q_GETQUOTA)
- oqctl.qc_cmd = Q_GETOQUOTA;
- else
- RETURN(-EINVAL);
+ struct obd_uuid *uuid = &qctl->obd_uuid;
- rc = -ENOENT;
obd = class_find_client_notype(uuid,
&sbi->ll_osc_exp->exp_obd->obd_uuid);
if (!obd)
- RETURN(rc);
+ GOTO(out_quotactl, rc = -ENOENT);
+
+ if (cmd == Q_GETINFO)
+ oqctl->qc_cmd = Q_GETOINFO;
+ else if (cmd == Q_GETQUOTA)
+ oqctl->qc_cmd = Q_GETOQUOTA;
+ else
+ GOTO(out_quotactl, rc = -EINVAL);
if (sbi->ll_mdc_exp->exp_obd == obd) {
- rc = obd_quotactl(sbi->ll_mdc_exp, &oqctl);
+ rc = obd_quotactl(sbi->ll_mdc_exp, oqctl);
} else {
int i;
struct obd_export *exp;
continue;
if (exp->exp_obd == obd) {
- rc = obd_quotactl(exp, &oqctl);
+ rc = obd_quotactl(exp, oqctl);
break;
}
}
}
- QCTLCONV(&qctl, &oqctl);
-
- if (copy_to_user((void *)arg, &qctl, sizeof(qctl)))
- RETURN(-EFAULT);
-
- RETURN(rc);
- }
+ oqctl->qc_cmd = cmd;
+ QCTL_COPY(qctl, oqctl);
- if (cmd == Q_SETQUOTA)
- oqctl.qc_dqblk.dqb_valid = QIF_LIMITS;
+ if (copy_to_user((void *)arg, qctl, sizeof(*qctl)))
+ rc = -EFAULT;
- rc = obd_quotactl(sbi->ll_mdc_exp, &oqctl);
- if (rc) {
- if (rc == -EBUSY && cmd == Q_QUOTAON)
- error = rc;
- else
- RETURN(rc);
+ GOTO(out_quotactl, rc);
}
- if (cmd == Q_QUOTAON || cmd == Q_QUOTAOFF) {
- rc = obd_quotactl(sbi->ll_osc_exp, &oqctl);
- if (rc) {
- if (rc != -EBUSY && cmd == Q_QUOTAON) {
- oqctl.qc_cmd = Q_QUOTAOFF;
- obd_quotactl(sbi->ll_mdc_exp, &oqctl);
- obd_quotactl(sbi->ll_osc_exp, &oqctl);
- }
- RETURN(rc);
- }
+ rc = obd_quotactl(sbi->ll_mdc_exp, oqctl);
+ if (rc && rc != -EBUSY && cmd == Q_QUOTAON) {
+ oqctl->qc_cmd = Q_QUOTAOFF;
+ obd_quotactl(sbi->ll_mdc_exp, oqctl);
}
- QCTLCONV(&qctl, &oqctl);
-
- if (copy_to_user((void *)arg, &qctl, sizeof(qctl)))
- return -EFAULT;
+ QCTL_COPY(qctl, oqctl);
- RETURN(rc?:error);
+ 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: {
unsigned int llap_write_queued:1,
llap_defer_uptodate:1,
llap_origin:3,
- llap_ra_used:1;
+ llap_ra_used:1,
+ llap_ignore_quota:1;
void *llap_cookie;
struct page *llap_page;
struct list_head llap_pending_write;
llap = LLAP_FROM_COOKIE(data);
ll_inode_fill_obdo(llap->llap_page->mapping->host, cmd, oa);
+
EXIT;
}
unsigned long size_index = inode->i_size >> PAGE_SHIFT;
struct obd_io_group *oig;
struct ll_sb_info *sbi = ll_i2sbi(inode);
- int rc, noquot = capable(CAP_SYS_RESOURCE) ? OBD_BRW_NOQUOTA : 0;
+ int rc, noquot = llap->llap_ignore_quota ? OBD_BRW_NOQUOTA : 0;
ENTRY;
/* _make_ready only sees llap once we've unlocked the page */
if (exp == NULL)
RETURN(-EINVAL);
+ llap->llap_ignore_quota = capable(CAP_SYS_RESOURCE);
+
/* queue a write for some time in the future the first time we
* dirty the page */
if (!PageDirty(page)) {
/* lproc_lov.c */
extern struct file_operations lov_proc_target_fops;
-/* Quota stuff */
-int lov_quotacheck(struct obd_export *exp, struct obd_quotactl *oqctl);
-int lov_quotactl(struct obd_export *exp, struct obd_quotactl *oqctl);
-
#endif
* Unset cookies should be all-zero (which will never occur naturally). */
static int lov_llog_origin_add(struct llog_ctxt *ctxt,
struct llog_rec_hdr *rec, struct lov_stripe_md *lsm,
- struct llog_cookie *logcookies, int numcookies,
- llog_fill_rec_cb_t fill_cb)
+ struct llog_cookie *logcookies, int numcookies)
{
struct obd_device *obd = ctxt->loc_obd;
struct lov_obd *lov = &obd->u.lov;
for (i = 0,loi = lsm->lsm_oinfo; i < lsm->lsm_stripe_count; i++,loi++) {
struct obd_device *child = lov->tgts[loi->loi_ost_idx].ltd_exp->exp_obd;
struct llog_ctxt *cctxt = llog_get_context(child, ctxt->loc_idx);
- struct llog_fill_rec_data data;
/* fill mds unlink/setattr log record */
- data.lfd_id = loi->loi_id;
- data.lfd_ogen = loi->loi_gr;
- fill_cb(rec, &data);
+ switch (rec->lrh_type) {
+ case MDS_UNLINK_REC: {
+ struct llog_unlink_rec *lur = (struct llog_unlink_rec *)rec;
+ lur->lur_oid = loi->loi_id;
+ lur->lur_ogen = loi->loi_gr;
+ break;
+ }
+ case MDS_SETATTR_REC: {
+ struct llog_setattr_rec *lsr = (struct llog_setattr_rec *)rec;
+ lsr->lsr_oid = loi->loi_id;
+ lsr->lsr_ogen = loi->loi_gr;
+ break;
+ }
+ default:
+ break;
+ }
rc += llog_add(cctxt, rec, NULL, logcookies + rc,
- numcookies - rc, fill_cb);
-
+ numcookies - rc);
}
RETURN(rc);
return lap->lap_caller_ops->ap_make_ready(lap->lap_caller_data, cmd);
}
+
static int lov_ap_refresh_count(void *data, int cmd)
{
struct lov_async_page *lap = LAP_FROM_COOKIE(data);
return lap->lap_caller_ops->ap_refresh_count(lap->lap_caller_data,
cmd);
}
+
static void lov_ap_fill_obdo(void *data, int cmd, struct obdo *oa)
{
struct lov_async_page *lap = LAP_FROM_COOKIE(data);
break;
default: {
int set = 0;
+
if (count == 0)
RETURN(-ENOTTY);
+
rc = 0;
for (i = 0; i < count; i++) {
int err;
err = obd_iocontrol(cmd, lov->tgts[i].ltd_exp,
len, karg, uarg);
- if (err) {
+ if (err == -ENODATA && cmd == OBD_IOC_POLL_QUOTACHECK) {
+ RETURN(err);
+ } else if (err) {
if (lov->tgts[i].active) {
CERROR("error: iocontrol OSC %s on OST "
"idx %d cmd %x: err = %d\n",
}
#endif
-
void lov_stripe_lock(struct lov_stripe_md *md)
{
LASSERT(md->lsm_lock_owner != current);
.o_llog_init = lov_llog_init,
.o_llog_finish = lov_llog_finish,
.o_notify = lov_notify,
-#ifdef HAVE_QUOTA_SUPPORT
- .o_quotacheck = lov_quotacheck,
- .o_quotactl = lov_quotactl,
-#endif
};
+static quota_interface_t *quota_interface = NULL;
+extern quota_interface_t lov_quota_interface;
+
int __init lov_init(void)
{
struct lprocfs_static_vars lvars;
ENTRY;
lprocfs_init_vars(lov, &lvars);
+
+ quota_interface = PORTAL_SYMBOL_GET(lov_quota_interface);
+ init_obd_quota_ops(quota_interface, &lov_obd_ops);
+
rc = class_register_type(&lov_obd_ops, lvars.module_vars,
OBD_LOV_DEVICENAME);
+ if (rc && quota_interface)
+ PORTAL_SYMBOL_PUT(osc_quota_interface);
+
RETURN(rc);
}
#ifdef __KERNEL__
static void /*__exit*/ lov_exit(void)
{
+ if (quota_interface)
+ PORTAL_SYMBOL_PUT(lov_quota_interface);
+
class_unregister_type(OBD_LOV_DEVICENAME);
}
-MODULES := lvfs #quotactl_test quotacheck_test
+MODULES := lvfs
@SERVER_TRUE@MODULES += fsfilt_@BACKINGFS@
lvfs-objs := lvfs_common.o lvfs_linux.o fsfilt.o upcall_cache.o
-#quotactl-objs := quotactl_test.o
-#quotaccheck-objs := quotacheck_test.o
ifeq ($(PATCHLEVEL),6)
fsfilt_@BACKINGFS@-objs := fsfilt-@BACKINGFS@.o
return 0;
}
+static const char *op_quotafile[] = { "lquota.user", "lquota.group" };
+
+#define DQINFO_COPY(out, in) \
+do { \
+ Q_COPY(out, in, dqi_bgrace); \
+ Q_COPY(out, in, dqi_igrace); \
+ Q_COPY(out, in, dqi_flags); \
+ Q_COPY(out, in, dqi_valid); \
+} while (0)
+
+#define DQBLK_COPY(out, in) \
+do { \
+ Q_COPY(out, in, dqb_bhardlimit); \
+ Q_COPY(out, in, dqb_bsoftlimit); \
+ Q_COPY(out, in, dqb_curspace); \
+ Q_COPY(out, in, dqb_ihardlimit); \
+ Q_COPY(out, in, dqb_isoftlimit); \
+ Q_COPY(out, in, dqb_curinodes); \
+ Q_COPY(out, in, dqb_btime); \
+ Q_COPY(out, in, dqb_itime); \
+ Q_COPY(out, in, dqb_valid); \
+} while (0)
+
+
+
+static int fsfilt_ext3_quotactl(struct super_block *sb,
+ struct obd_quotactl *oqc)
+{
+ int i, rc = 0, error = 0;
+ struct quotactl_ops *qcop;
+ struct if_dqinfo *info;
+ struct if_dqblk *dqblk;
+ ENTRY;
+
+ if (!sb->s_qcop)
+ RETURN(-ENOSYS);
+
+ OBD_ALLOC_PTR(info);
+ if (!info)
+ RETURN(-ENOMEM);
+ OBD_ALLOC_PTR(dqblk);
+ if (!dqblk) {
+ OBD_FREE_PTR(info);
+ RETURN(-ENOMEM);
+ }
+
+ DQINFO_COPY(info, &oqc->qc_dqinfo);
+ DQBLK_COPY(dqblk, &oqc->qc_dqblk);
+
+ qcop = sb->s_qcop;
+ if (oqc->qc_cmd == Q_QUOTAON || oqc->qc_cmd == Q_QUOTAOFF) {
+ for (i = 0; i < MAXQUOTAS; i++) {
+ if (!Q_TYPESET(oqc, i))
+ continue;
+
+ if (oqc->qc_cmd == Q_QUOTAON) {
+ if (!qcop->quota_on)
+ GOTO(out, rc = -ENOSYS);
+ rc = qcop->quota_on(sb, i, oqc->qc_id,
+ (char *)op_quotafile[i]);
+ } else if (oqc->qc_cmd == Q_QUOTAOFF) {
+ if (!qcop->quota_off)
+ GOTO(out, rc = -ENOSYS);
+ rc = qcop->quota_off(sb, i);
+ }
+
+ if (rc == -EBUSY)
+ error = rc;
+ else if (rc)
+ GOTO(out, rc);
+ }
+ GOTO(out, rc ?: error);
+ }
+
+ switch (oqc->qc_cmd) {
+ case Q_GETOINFO:
+ case Q_GETINFO:
+ if (!qcop->get_info)
+ GOTO(out, rc = -ENOSYS);
+ rc = qcop->get_info(sb, oqc->qc_type, info);
+ break;
+ case Q_SETQUOTA:
+ case Q_INITQUOTA:
+ if (!qcop->set_dqblk)
+ GOTO(out, rc = -ENOSYS);
+ rc = qcop->set_dqblk(sb, oqc->qc_type, oqc->qc_id, dqblk);
+ break;
+ case Q_GETOQUOTA:
+ case Q_GETQUOTA:
+ if (!qcop->get_dqblk)
+ GOTO(out, rc = -ENOSYS);
+ rc = qcop->get_dqblk(sb, oqc->qc_type, oqc->qc_id, dqblk);
+ break;
+ case Q_SYNC:
+ if (!sb->s_qcop->quota_sync)
+ GOTO(out, rc = -ENOSYS);
+ qcop->quota_sync(sb, oqc->qc_type);
+ break;
+ default:
+ CERROR("unsupported quotactl command: %d", oqc->qc_cmd);
+ LBUG();
+ }
+out:
+ DQINFO_COPY(&oqc->qc_dqinfo, info);
+ DQBLK_COPY(&oqc->qc_dqblk, dqblk);
+
+ OBD_FREE_PTR(info);
+ OBD_FREE_PTR(dqblk);
+
+ if (rc)
+ CDEBUG(D_QUOTA, "quotactl command %#x, id %u, type %d "
+ "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 */
+};
+
+static inline unsigned int const
+chkquot_hash(qid_t id, int type)
+{
+ return (id * (MAXQUOTAS - type)) % NR_DQHASH;
+}
+
+static inline struct chk_dqblk *
+find_chkquot(struct hlist_head *head, qid_t id, int type)
+{
+ struct hlist_node *node;
+ struct chk_dqblk *cdqb;
+
+ hlist_for_each(node, head) {
+ cdqb = hlist_entry(node, struct chk_dqblk, dqb_hash);
+ if (cdqb->dqb_id == id && cdqb->dqb_type == type)
+ return cdqb;
+ }
+
+ return NULL;
+}
+
+static struct chk_dqblk *alloc_chkquot(qid_t id, int type)
+{
+ struct chk_dqblk *cdqb;
+
+ OBD_ALLOC_PTR(cdqb);
+ if (cdqb) {
+ INIT_HLIST_NODE(&cdqb->dqb_hash);
+ INIT_LIST_HEAD(&cdqb->dqb_list);
+ cdqb->dqb_id = id;
+ cdqb->dqb_type = type;
+ }
+
+ return cdqb;
+}
+
+static struct chk_dqblk *
+cqget(struct super_block *sb, struct hlist_head *hash, struct list_head *list,
+ qid_t id, int type, int first_check)
+{
+ struct hlist_head *head = hash + chkquot_hash(id, type);
+ struct if_dqblk dqb;
+ struct chk_dqblk *cdqb;
+ int rc;
+
+ cdqb = find_chkquot(head, id, type);
+ if (cdqb)
+ return cdqb;
+
+ cdqb = alloc_chkquot(id, type);
+ if (!cdqb)
+ return NULL;
+
+ if (!first_check) {
+ rc = sb->s_qcop->get_dqblk(sb, type, id, &dqb);
+ if (rc) {
+ CERROR("get_dqblk of id %u, type %d failed: %d\n",
+ id, type, rc);
+ } else {
+ DQBLK_COPY(cdqb, &dqb);
+ cdqb->dqb_curspace = 0;
+ cdqb->dqb_curinodes = 0;
+ }
+ }
+
+ hlist_add_head(&cdqb->dqb_hash, head);
+ list_add_tail(&cdqb->dqb_list, list);
+
+ return cdqb;
+}
+
+static inline int quota_onoff(struct super_block *sb, int cmd, int type)
+{
+ struct obd_quotactl *oqctl;
+ int rc;
+
+ OBD_ALLOC_PTR(oqctl);
+ if (!oqctl)
+ RETURN(-ENOMEM);
+
+ oqctl->qc_cmd = cmd;
+ oqctl->qc_id = QFMT_LDISKFS;
+ oqctl->qc_type = type;
+ rc = fsfilt_ext3_quotactl(sb, oqctl);
+
+ OBD_FREE_PTR(oqctl);
+ return rc;
+}
+
+static inline int read_old_dqinfo(struct super_block *sb, int type,
+ struct if_dqinfo *dqinfo)
+{
+ struct obd_quotactl *oqctl;
+ int rc;
+ ENTRY;
+
+ OBD_ALLOC_PTR(oqctl);
+ if (!oqctl)
+ RETURN(-ENOMEM);
+
+ oqctl->qc_cmd = Q_GETINFO;
+ oqctl->qc_type = type;
+ rc = fsfilt_ext3_quotactl(sb, oqctl);
+ if (!rc)
+ ((struct obd_dqinfo *)dqinfo)[type] = oqctl->qc_dqinfo;
+
+ OBD_FREE_PTR(oqctl);
+ RETURN(rc);
+}
+
static inline struct ext3_group_desc *
get_group_desc(struct super_block *sb, int group)
{
return inode;
}
+struct qchk_ctxt {
+ struct hlist_head qckt_hash[NR_DQHASH]; /* quotacheck hash */
+ struct list_head qckt_list; /* quotacheck list */
+ int qckt_first_check[MAXQUOTAS]; /* 1 if no old quotafile */
+ struct if_dqinfo qckt_dqinfo[MAXQUOTAS]; /* old dqinfo */
+};
+
+static int add_inode_quota(struct inode *inode, struct qchk_ctxt *qctxt,
+ struct obd_quotactl *oqc)
+{
+ struct chk_dqblk *cdqb[MAXQUOTAS] = { NULL, };
+ loff_t size = 0;
+ qid_t qid[MAXQUOTAS];
+ int cnt, i, rc = 0;
+
+ if (!inode)
+ return 0;
+
+ qid[USRQUOTA] = inode->i_uid;
+ qid[GRPQUOTA] = inode->i_gid;
+
+ if (S_ISDIR(inode->i_mode) ||
+ S_ISREG(inode->i_mode) ||
+ S_ISLNK(inode->i_mode))
+ size = inode_get_bytes(inode);
+
+ for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+ if (!Q_TYPESET(oqc, cnt))
+ continue;
+
+ cdqb[cnt] = cqget(inode->i_sb, qctxt->qckt_hash,
+ &qctxt->qckt_list, qid[cnt], cnt,
+ qctxt->qckt_first_check[cnt]);
+ if (!cdqb[cnt]) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ cdqb[cnt]->dqb_curspace += size;
+ cdqb[cnt]->dqb_curinodes++;
+ }
+
+ if (rc) {
+ for (i = 0; i < cnt; i++) {
+ if (!Q_TYPESET(oqc, i))
+ continue;
+ LASSERT(cdqb[i]);
+ cdqb[i]->dqb_curspace -= size;
+ cdqb[i]->dqb_curinodes--;
+ }
+ }
+
+ 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)
+{
+ struct v2_disk_dqinfo dqinfo;
+ __u32 blocks = V2_DQTREEOFF + 1;
+ loff_t offset = V2_DQINFOOFF;
+
+ if (info) {
+ dqinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
+ dqinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
+ dqinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK &
+ ~DQF_INFO_DIRTY);
+ } else {
+ dqinfo.dqi_bgrace = cpu_to_le32(MAX_DQ_TIME);
+ dqinfo.dqi_igrace = cpu_to_le32(MAX_IQ_TIME);
+ dqinfo.dqi_flags = 0;
+ }
+
+ dqinfo.dqi_blocks = cpu_to_le32(blocks);
+ dqinfo.dqi_free_blk = 0;
+ dqinfo.dqi_free_entry = 0;
+
+ return cfs_user_write(f, (char *)&dqinfo, sizeof(dqinfo), &offset);
+}
+
+static int create_new_quota_files(struct qchk_ctxt *qctxt,
+ struct obd_quotactl *oqc)
+{
+ int i, rc = 0;
+ ENTRY;
+
+ for (i = 0; i < MAXQUOTAS; i++) {
+ struct if_dqinfo *info = qctxt->qckt_first_check[i]?
+ NULL : &qctxt->qckt_dqinfo[i];
+ struct file *file;
+
+ if (!Q_TYPESET(oqc, i))
+ continue;
+
+ file = filp_open(op_quotafile[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);
+ GOTO(out, rc);
+ }
+
+ if (!S_ISREG(file->f_dentry->d_inode->i_mode)) {
+ CERROR("file %s is not regular", op_quotafile[i]);
+ filp_close(file, 0);
+ GOTO(out, rc = -EINVAL);
+ }
+
+ rc = v2_write_dqheader(file, i);
+ if (rc) {
+ filp_close(file, 0);
+ GOTO(out, rc);
+ }
+
+ rc = v2_write_dqinfo(file, i, info);
+ filp_close(file, 0);
+ if (rc)
+ GOTO(out, rc);
+ }
+
+out:
+ RETURN(rc);
+}
+
+
+static int commit_chkquot(struct super_block *sb, struct qchk_ctxt *qctxt,
+ struct chk_dqblk *cdqb)
+{
+ struct obd_quotactl *oqc;
+ struct timeval now;
+ int rc;
+ ENTRY;
+
+ OBD_ALLOC_PTR(oqc);
+ if (!oqc)
+ RETURN(-ENOMEM);
+
+ do_gettimeofday(&now);
+
+ if (cdqb->dqb_bsoftlimit &&
+ toqb(cdqb->dqb_curspace) >= cdqb->dqb_bsoftlimit &&
+ !cdqb->dqb_btime)
+ cdqb->dqb_btime = now.tv_sec +
+ qctxt->qckt_dqinfo[cdqb->dqb_type].dqi_bgrace;
+
+ if (cdqb->dqb_isoftlimit &&
+ cdqb->dqb_curinodes >= cdqb->dqb_isoftlimit &&
+ !cdqb->dqb_itime)
+ cdqb->dqb_itime = now.tv_sec +
+ qctxt->qckt_dqinfo[cdqb->dqb_type].dqi_igrace;
+
+ cdqb->dqb_valid = QIF_ALL;
+
+ oqc->qc_cmd = Q_SETQUOTA;
+ oqc->qc_type = cdqb->dqb_type;
+ oqc->qc_id = cdqb->dqb_id;
+ DQBLK_COPY(&oqc->qc_dqblk, cdqb);
+
+ rc = fsfilt_ext3_quotactl(sb, oqc);
+ OBD_FREE_PTR(oqc);
+ RETURN(rc);
+}
+
+static int prune_chkquots(struct super_block *sb,
+ struct qchk_ctxt *qctxt, int error)
+{
+ struct chk_dqblk *cdqb, *tmp;
+ int rc;
+
+ list_for_each_entry_safe(cdqb, tmp, &qctxt->qckt_list, dqb_list) {
+ if (!error) {
+ rc = commit_chkquot(sb, qctxt, cdqb);
+ if (rc)
+ error = rc;
+ }
+ hlist_del_init(&cdqb->dqb_hash);
+ list_del(&cdqb->dqb_list);
+ OBD_FREE_PTR(cdqb);
+ }
+
+ return error;
+}
+
+static int fsfilt_ext3_quotacheck(struct super_block *sb,
+ struct obd_quotactl *oqc)
+{
+ struct ext3_sb_info *sbi = EXT3_SB(sb);
+ int i, group;
+ struct qchk_ctxt *qctxt;
+ struct buffer_head *bitmap_bh = NULL;
+ unsigned long ino;
+ struct inode *inode;
+ int rc = 0;
+ ENTRY;
+
+ /* turn on quota and read dqinfo if existed */
+ OBD_ALLOC_PTR(qctxt);
+ if (!qctxt) {
+ oqc->qc_stat = -ENOMEM;
+ RETURN(-ENOMEM);
+ }
+
+ for (i = 0; i < NR_DQHASH; i++)
+ INIT_HLIST_HEAD(&qctxt->qckt_hash[i]);
+ INIT_LIST_HEAD(&qctxt->qckt_list);
+
+ for (i = 0; i < MAXQUOTAS; i++) {
+ if (!Q_TYPESET(oqc, i))
+ continue;
+
+ rc = quota_onoff(sb, Q_QUOTAON, i);
+ if (!rc || rc == -EBUSY) {
+ rc = read_old_dqinfo(sb, i, qctxt->qckt_dqinfo);
+ if (rc)
+ GOTO(out, rc);
+ } else if (rc == -ENOENT) {
+ qctxt->qckt_first_check[i] = 1;
+ } else if (rc) {
+ GOTO(out, rc);
+ }
+ }
+
+ /* check quota and update in hash */
+ for (group = 0; group < sbi->s_groups_count; group++) {
+ ino = group * sbi->s_inodes_per_group + 1;
+ bitmap_bh = read_inode_bitmap(sb, group);
+ if (!bitmap_bh) {
+ CERROR("read_inode_bitmap group %d failed", group);
+ GOTO(out, -EIO);
+ }
+
+ for (i = 0; i < sbi->s_inodes_per_group; i++, ino++) {
+ if (ino < sbi->s_first_ino)
+ continue;
+
+ inode = ext3_iget_inuse(sb, bitmap_bh, i, ino);
+ rc = add_inode_quota(inode, qctxt, oqc);
+ iput(inode);
+ if (rc) {
+ brelse(bitmap_bh);
+ GOTO(out, rc);
+ }
+ }
+
+ brelse(bitmap_bh);
+ }
+
+ /* turn off quota cause we are to dump chk_dqblk to files */
+ quota_onoff(sb, Q_QUOTAOFF, oqc->qc_type);
+
+ 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);
+out:
+ /* dump and free chk_dqblk */
+ rc = prune_chkquots(sb, qctxt, rc);
+ OBD_FREE_PTR(qctxt);
+
+ /* turn off quota, `lfs quotacheck` will turn on when all
+ * nodes quotacheck finish. */
+ quota_onoff(sb, Q_QUOTAOFF, oqc->qc_type);
+
+ oqc->qc_stat = rc;
+ if (rc)
+ CERROR("quotacheck failed: rc = %d\n", rc);
+
+ RETURN(rc);
+}
+
#ifdef HAVE_QUOTA_SUPPORT
-# include "fsfilt_ext3_quota.h"
+static int fsfilt_ext3_quotainfo(struct lustre_quota_info *lqi, int type,
+ int cmd, struct list_head *list)
+{
+ int rc = 0;
+ ENTRY;
+
+ if (lqi->qi_files[type] == NULL) {
+ CERROR("operate qinfo before it's enabled!\n");
+ RETURN(-EIO);
+ }
+
+ switch (cmd) {
+ case QFILE_CHK:
+ rc = lustre_check_quota_file(lqi, type);
+ break;
+ case QFILE_RD_INFO:
+ rc = lustre_read_quota_info(lqi, type);
+ break;
+ case QFILE_WR_INFO:
+ rc = lustre_write_quota_info(lqi, type);
+ break;
+ case QFILE_INIT_INFO:
+ rc = lustre_init_quota_info(lqi, type);
+ break;
+ case QFILE_GET_QIDS:
+ rc = lustre_get_qids(lqi, type, list);
+ break;
+ default:
+ CERROR("Unsupported admin quota file cmd %d\n", cmd);
+ LBUG();
+ break;
+ }
+ RETURN(rc);
+}
+
+static int fsfilt_ext3_dquot(struct lustre_dquot *dquot, int cmd)
+{
+ int rc = 0;
+ ENTRY;
+
+ if (dquot->dq_info->qi_files[dquot->dq_type] == NULL) {
+ CERROR("operate dquot before it's enabled!\n");
+ RETURN(-EIO);
+ }
+
+ switch (cmd) {
+ case QFILE_RD_DQUOT:
+ rc = lustre_read_dquot(dquot);
+ break;
+ case QFILE_WR_DQUOT:
+ if (dquot->dq_dqb.dqb_ihardlimit ||
+ dquot->dq_dqb.dqb_isoftlimit ||
+ dquot->dq_dqb.dqb_bhardlimit ||
+ dquot->dq_dqb.dqb_bsoftlimit)
+ clear_bit(DQ_FAKE_B, &dquot->dq_flags);
+ else
+ set_bit(DQ_FAKE_B, &dquot->dq_flags);
+
+ rc = lustre_commit_dquot(dquot);
+ if (rc >= 0)
+ rc = 0;
+ break;
+ default:
+ CERROR("Unsupported admin quota file cmd %d\n", cmd);
+ LBUG();
+ break;
+ }
+ RETURN(rc);
+}
#endif
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,
-#ifdef HAVE_QUOTA_SUPPORT
.fs_quotactl = fsfilt_ext3_quotactl,
.fs_quotacheck = fsfilt_ext3_quotacheck,
+#ifdef HAVE_QUOTA_SUPPORT
.fs_quotainfo = fsfilt_ext3_quotainfo,
.fs_dquot = fsfilt_ext3_dquot,
#endif
}
/* Quota stuff */
-#ifdef HAVE_QUOTA_SUPPORT
-int mdc_quotacheck(struct obd_export *exp, struct obd_quotactl *oqctl);
-int mdc_poll_quotacheck(struct obd_export *exp, struct if_quotacheck *qchk);
-int mdc_quotactl(struct obd_export *exp, struct obd_quotactl *oqctl);
-#else
-static inline int mdc_quotacheck(struct obd_export *exp, struct obd_quotactl *oqctl)
-{
- return -ENOTSUPP;
-}
-
-static inline int mdc_poll_quotacheck(struct obd_export *exp, struct if_quotacheck *qchk)
-{
- return -ENOTSUPP;
-}
-
-static inline int mdc_quotactl(struct obd_export *exp, struct obd_quotactl *oqctl)
-{
- return -ENOTSUPP;
-}
-#endif
-
+extern quota_interface_t *quota_interface;
return rc;
}
+
static int mdc_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
void *karg, void *uarg)
{
}
#endif
case OBD_IOC_POLL_QUOTACHECK:
- rc = mdc_poll_quotacheck(exp, (struct if_quotacheck *)karg);
+ rc = lquota_poll_check(quota_interface, exp,
+ (struct if_quotacheck *)karg);
GOTO(out, rc);
default:
CERROR("mdc_ioctl(): unrecognised ioctl %#x\n", cmd);
.o_import_event = mdc_import_event,
.o_llog_init = mdc_llog_init,
.o_llog_finish = mdc_llog_finish,
- .o_quotacheck = mdc_quotacheck,
- .o_quotactl = mdc_quotactl,
};
+static quota_interface_t *quota_interface = NULL;
+extern quota_interface_t mdc_quota_interface;
+
int __init mdc_init(void)
{
+ int rc;
struct lprocfs_static_vars lvars;
lprocfs_init_vars(mdc, &lvars);
- return class_register_type(&mdc_obd_ops, lvars.module_vars,
- LUSTRE_MDC_NAME);
+
+ quota_interface = PORTAL_SYMBOL_GET(mdc_quota_interface);
+ init_obd_quota_ops(quota_interface, &mdc_obd_ops);
+
+ rc = class_register_type(&mdc_obd_ops, lvars.module_vars,
+ LUSTRE_MDC_NAME);
+ if (rc && quota_interface)
+ PORTAL_SYMBOL_PUT(osc_quota_interface);
+
+ RETURN(rc);
}
#ifdef __KERNEL__
static void /*__exit*/ mdc_exit(void)
{
+ if (quota_interface)
+ PORTAL_SYMBOL_PUT(mdc_quota_interface);
+
class_unregister_type(LUSTRE_MDC_NAME);
}
mds-objs := mds_log.o mds_unlink_open.o mds_lov.o handler.o mds_reint.o
mds-objs += mds_fs.o lproc_mds.o mds_open.o mds_lib.o mds_xattr.o
-ifeq ($(PATCHLEVEL),6)
-#mds-objs += quota_master.o
-endif
-
@INCLUDE_RULES@
snprintf(fid_name, sizeof(fid_name), "0x%lx", ino);
CDEBUG(D_DENTRY, "--> mds_fid2dentry: ino/gen %lu/%u, sb %p\n",
- ino, generation, mds->mds_sb);
+ ino, generation, mds->mds_obt.obt_sb);
/* under ext3 this is neither supposed to return bad inodes
nor NULL inodes. */
int rc;
spin_lock(&obd->obd_osfs_lock);
- rc = fsfilt_statfs(obd, obd->u.mds.mds_sb, max_age);
+ rc = fsfilt_statfs(obd, obd->u.obt.obt_sb, max_age);
if (rc == 0)
memcpy(osfs, &obd->obd_osfs, sizeof(*osfs));
spin_unlock(&obd->obd_osfs_lock);
if (body->fid1.id == 0) {
/* a fid of zero is taken to mean "sync whole filesystem" */
- rc = fsfilt_sync(obd, mds->mds_sb);
+ rc = fsfilt_sync(obd, obd->u.obt.obt_sb);
GOTO(out, rc);
} else {
struct dentry *de;
RETURN(0);
}
+static int mds_handle_quotacheck(struct ptlrpc_request *req)
+{
+ struct obd_quotactl *oqctl;
+ int rc;
+ ENTRY;
+
+ oqctl = lustre_swab_reqbuf(req, 0, sizeof(*oqctl),
+ lustre_swab_obd_quotactl);
+ if (oqctl == NULL)
+ RETURN(-EPROTO);
+
+ rc = lustre_pack_reply(req, 0, NULL, NULL);
+ if (rc) {
+ CERROR("mds: out of memory while packing quotacheck reply\n");
+ RETURN(rc);
+ }
+
+ req->rq_status = obd_quotacheck(req->rq_export, oqctl);
+ RETURN(0);
+}
+
+static int mds_handle_quotactl(struct ptlrpc_request *req)
+{
+ struct obd_quotactl *oqctl, *repoqc;
+ int rc, size = sizeof(*repoqc);
+ ENTRY;
+
+ oqctl = lustre_swab_reqbuf(req, 0, sizeof(*oqctl),
+ lustre_swab_obd_quotactl);
+ if (oqctl == NULL)
+ RETURN(-EPROTO);
+
+ rc = lustre_pack_reply(req, 1, &size, NULL);
+ if (rc)
+ RETURN(rc);
+
+ repoqc = lustre_msg_buf(req->rq_repmsg, 0, sizeof(*repoqc));
+
+ req->rq_status = obd_quotactl(req->rq_export, oqctl);
+ *repoqc = *oqctl;
+ RETURN(0);
+}
int mds_handle(struct ptlrpc_request *req)
{
case MDS_QUOTACHECK:
DEBUG_REQ(D_INODE, req, "quotacheck");
OBD_FAIL_RETURN(OBD_FAIL_MDS_QUOTACHECK_NET, 0);
- rc = mds_quotacheck(req);
+ rc = mds_handle_quotacheck(req);
break;
case MDS_QUOTACTL:
DEBUG_REQ(D_INODE, req, "quotactl");
OBD_FAIL_RETURN(OBD_FAIL_MDS_QUOTACTL_NET, 0);
- rc = mds_quotactl(req);
+ rc = mds_handle_quotactl(req);
break;
case OBD_PING:
int rc = 0;
ENTRY;
+ CLASSERT(offsetof(struct obd_device, u.obt) ==
+ offsetof(struct obd_device, u.mds.mds_obt));
+
if (lcfg->lcfg_bufcount < 3)
RETURN(rc = -EINVAL);
"mds_ldlm_client", &obd->obd_ldlm_client);
obd->obd_replayable = 1;
+ rc = lquota_setup(quota_interface, obd, lcfg);
+ if (rc)
+ GOTO(err_fs, rc);
+
mds->mds_group_hash = upcall_cache_init(obd->obd_name);
if (IS_ERR(mds->mds_group_hash)) {
rc = PTR_ERR(mds->mds_group_hash);
mds->mds_group_hash = NULL;
- GOTO(err_fs, rc);
+ GOTO(err_qctxt, rc);
}
- mds_quota_setup(mds);
-
/* Wait for mds_postrecov trying to clear orphans until 9439 is fixed */
obd->obd_async_recov = 0;
rc = mds_postsetup(obd);
if (rc)
- GOTO(err_fs, rc);
+ GOTO(err_qctxt, rc);
obd->obd_async_recov = 0;
lprocfs_init_vars(mds, &lvars);
RETURN(0);
+err_qctxt:
+ lquota_cleanup(quota_interface, obd);
err_fs:
/* No extra cleanup needed for llog_init_commit_thread() */
mds_fs_cleanup(obd);
err_put:
unlock_kernel();
mntput(mds->mds_vfsmnt);
- mds->mds_sb = 0;
+ obd->u.obt.obt_sb = NULL;
lock_kernel();
err_ops:
fsfilt_put_ops(obd->obd_fsops);
/* Does anyone need this to be synchronous ever? */
mds_lov_start_synchronize(obd, NULL, obd->obd_async_recov);
+ /* quota recovery */
+ lquota_recovery(quota_interface, obd);
+
out:
RETURN(rc < 0 ? rc : item);
}
ping_evictor_stop();
- if (mds->mds_sb == NULL)
+ if (obd->u.obt.obt_sb == NULL)
RETURN(0);
- save_dev = lvfs_sbdev(mds->mds_sb);
+ save_dev = lvfs_sbdev(obd->u.obt.obt_sb);
if (mds->mds_osc_exp)
/* lov export was disconnected by mds_lov_clean;
lprocfs_obd_cleanup(obd);
- mds_quota_cleanup(mds);
+ lquota_cleanup(quota_interface, obd);
mds_update_server_data(obd, 1);
if (mds->mds_lov_objids != NULL) {
}
mntput(mds->mds_vfsmnt);
- mds->mds_sb = NULL;
+ obd->u.obt.obt_sb = NULL;
ldlm_namespace_free(obd->obd_namespace, obd->obd_force);
.o_health_check = mdt_health_check,
};
+quota_interface_t *quota_interface = NULL;
+extern quota_interface_t mds_quota_interface;
+
static int __init mds_init(void)
{
int rc;
struct lprocfs_static_vars lvars;
- rc = lustre_dquot_init();
- if (rc)
+ quota_interface = PORTAL_SYMBOL_GET(mds_quota_interface);
+ rc = lquota_init(quota_interface);
+ if (rc) {
+ if (quota_interface)
+ PORTAL_SYMBOL_PUT(mds_quota_interface);
return rc;
-
+ }
+ init_obd_quota_ops(quota_interface, &mds_obd_ops);
+
lprocfs_init_vars(mds, &lvars);
class_register_type(&mds_obd_ops, lvars.module_vars, LUSTRE_MDS_NAME);
lprocfs_init_vars(mdt, &lvars);
static void /*__exit*/ mds_exit(void)
{
- lustre_dquot_exit();
+ lquota_exit(quota_interface);
+ if (quota_interface)
+ PORTAL_SYMBOL_PUT(mds_quota_interface);
class_unregister_type(LUSTRE_MDS_NAME);
class_unregister_type(LUSTRE_MDT_NAME);
return count;
}
+#ifdef HAVE_QUOTA_SUPPORT
+static int lprocfs_mds_rd_bunit(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ LASSERT(obd != NULL);
+
+ return snprintf(page, count, "%lu\n",
+ obd->u.obt.obt_qctxt.lqc_bunit_sz);
+}
+
+static int lprocfs_mds_rd_iunit(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ LASSERT(obd != NULL);
+
+ return snprintf(page, count, "%lu\n",
+ obd->u.obt.obt_qctxt.lqc_iunit_sz);
+}
+
+static int lprocfs_mds_wr_bunit(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ int val, rc;
+ LASSERT(obd != NULL);
+
+ rc = lprocfs_write_helper(buffer, count, &val);
+ if (rc)
+ return rc;
+
+ if (val % QUOTABLOCK_SIZE ||
+ val <= obd->u.obt.obt_qctxt.lqc_btune_sz)
+ return -EINVAL;
+
+ obd->u.obt.obt_qctxt.lqc_bunit_sz = val;
+ return count;
+}
+
+static int lprocfs_mds_wr_iunit(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ int val, rc;
+ LASSERT(obd != NULL);
+
+ rc = lprocfs_write_helper(buffer, count, &val);
+ if (rc)
+ return rc;
+
+ if (val <= obd->u.obt.obt_qctxt.lqc_itune_sz)
+ return -EINVAL;
+
+ obd->u.obt.obt_qctxt.lqc_iunit_sz = val;
+ return count;
+}
+
+static int lprocfs_mds_rd_btune(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ LASSERT(obd != NULL);
+
+ return snprintf(page, count, "%lu\n",
+ obd->u.obt.obt_qctxt.lqc_btune_sz);
+}
+
+static int lprocfs_mds_rd_itune(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ LASSERT(obd != NULL);
+
+ return snprintf(page, count, "%lu\n",
+ obd->u.obt.obt_qctxt.lqc_itune_sz);
+}
+
+static int lprocfs_mds_wr_btune(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ int val, rc;
+ LASSERT(obd != NULL);
+
+ rc = lprocfs_write_helper(buffer, count, &val);
+ if (rc)
+ return rc;
+
+ if (val <= QUOTABLOCK_SIZE * MIN_QLIMIT || val % QUOTABLOCK_SIZE ||
+ val >= obd->u.obt.obt_qctxt.lqc_bunit_sz)
+ return -EINVAL;
+
+ obd->u.obt.obt_qctxt.lqc_btune_sz = val;
+ return count;
+}
+
+static int lprocfs_mds_wr_itune(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ int val, rc;
+ LASSERT(obd != NULL);
+
+ rc = lprocfs_write_helper(buffer, count, &val);
+ if (rc)
+ return rc;
+
+ if (val <= MIN_QLIMIT ||
+ val >= obd->u.obt.obt_qctxt.lqc_iunit_sz)
+ return -EINVAL;
+
+ obd->u.obt.obt_qctxt.lqc_itune_sz = val;
+ return count;
+}
+#endif
+
struct lprocfs_vars lprocfs_mds_obd_vars[] = {
{ "uuid", lprocfs_rd_uuid, 0, 0 },
{ "blocksize", lprocfs_rd_blksize, 0, 0 },
RETURN(rc);
mds->mds_vfsmnt = mnt;
- mds->mds_sb = mnt->mnt_root->d_inode->i_sb;
+ obd->u.obt.obt_sb = mnt->mnt_root->d_inode->i_sb;
- fsfilt_setup(obd, mds->mds_sb);
+ fsfilt_setup(obd, obd->u.obt.obt_sb);
OBD_SET_CTXT_MAGIC(&obd->obd_lvfs_ctxt);
obd->obd_lvfs_ctxt.pwdmnt = mnt;
mds->mds_pending_dir = NULL;
}
- mds_fs_quota_cleanup(mds);
-
+ lquota_fs_cleanup(quota_interface, obd);
+
pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
shrink_dcache_parent(mds->mds_fid_de);
dput(mds->mds_fid_de);
- LL_DQUOT_OFF(mds->mds_sb);
+ LL_DQUOT_OFF(obd->u.obt.obt_sb);
return rc;
}
struct lustre_msg *repmsg, struct mds_body *repbody,
int repoff);
+/* quota stuff */
+extern quota_interface_t *quota_interface;
+
/* mds/mds_xattr.c */
int mds_setxattr(struct ptlrpc_request *req);
int mds_getxattr(struct ptlrpc_request *req);
-/* mds/quota_master.c */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) && defined (HAVE_QUOTA_SUPPORT)
-int lustre_dquot_init(void);
-void lustre_dquot_exit(void);
-int dqacq_handler(struct obd_device *obd, struct qunit_data *qdata, int opc);
-void mds_adjust_qunit(struct obd_device *obd, uid_t cuid, gid_t cgid,
- uid_t puid, gid_t pgid, int rc);
-int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl);
-int mds_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl);
-int mds_quota_off(struct obd_device *obd, struct obd_quotactl *oqctl);
-int mds_set_dqinfo(struct obd_device *obd, struct obd_quotactl *oqctl);
-int mds_get_dqinfo(struct obd_device *obd, struct obd_quotactl *oqctl);
-int mds_set_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl);
-int mds_get_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl);
-#else
-static inline int lustre_dquot_init(void) { return 0; }
-static inline void lustre_dquot_exit(void) { return; }
-static inline int dqacq_handler(struct obd_device *obd,
- struct qunit_data *qdata, int opc) {return 0;}
-static inline void mds_adjust_qunit(struct obd_device *obd, uid_t cuid,
- gid_t cgid, uid_t puid,
- gid_t pgid, int rc) { return; }
-static inline int init_admin_quotafiles(struct obd_device *obd,
- struct obd_quotactl *oqctl) {return 0;}
-static inline int mds_quota_on(struct obd_device *obd,
- struct obd_quotactl *oqctl) { return 0; }
-static inline int mds_quota_off(struct obd_device *obd,
- struct obd_quotactl *oqctl) { return 0; }
-static inline int mds_set_dqinfo(struct obd_device *obd,
- struct obd_quotactl *oqctl) { return 0; }
-static inline int mds_get_dqinfo(struct obd_device *obd,
- struct obd_quotactl *oqctl) { return 0; }
-static inline int mds_set_dqblk(struct obd_device *obd,
- struct obd_quotactl *oqctl) { return 0; }
-static inline int mds_get_dqblk(struct obd_device *obd,
- struct obd_quotactl *oqctl) { return 0; }
-#endif /* KERNEL_VERSION(2,5,0) && QUOTA */
-
-#ifdef HAVE_QUOTA_SUPPORT
-/* Internal quota stuff */
-int mds_quotacheck(struct ptlrpc_request *req);
-int mds_quotactl(struct ptlrpc_request *req);
-void mds_quota_setup(struct mds_obd *mds);
-void mds_quota_cleanup(struct mds_obd *mds);
-void mds_fs_quota_cleanup(struct mds_obd *mds);
-
-#ifdef LPROCFS
-int lprocfs_mds_rd_bunit(char *page, char **start, off_t off, int count,
- int *eof, void *data);
-int lprocfs_mds_rd_iunit(char *page, char **start, off_t off, int count,
- int *eof, void *data);
-int lprocfs_mds_wr_bunit(struct file *file, const char *buffer,
- unsigned long count, void *data);
-int lprocfs_mds_wr_iunit(struct file *file, const char *buffer,
- unsigned long count, void *data);
-int lprocfs_mds_rd_btune(char *page, char **start, off_t off, int count,
- int *eof, void *data);
-int lprocfs_mds_rd_itune(char *page, char **start, off_t off, int count,
- int *eof, void *data);
-int lprocfs_mds_wr_btune(struct file *file, const char *buffer,
- unsigned long count, void *data);
-int lprocfs_mds_wr_itune(struct file *file, const char *buffer,
- unsigned long count, void *data);
-#endif /* LPROCFS */
-#else /* QUOTA */
-static inline int mds_quotacheck(struct ptlrpc_request *req)
-{
- req->rq_status = -EOPNOTSUPP;
- return -EOPNOTSUPP;
-}
-static inline int mds_quotactl(struct ptlrpc_request *req)
-{
- req->rq_status = -EOPNOTSUPP;
- return -EOPNOTSUPP;
-}
-static inline void mds_quota_setup(struct mds_obd *mds) {}
-static inline void mds_quota_cleanup(struct mds_obd *mds) {}
-static inline void mds_fs_quota_cleanup(struct mds_obd *mds) {}
-#endif /* Quota */
-
-
#endif /* _MDS_INTERNAL_H */
#include "mds_internal.h"
-/* callback function of lov to fill unlink log record */
-static int mds_log_fill_unlink_rec(struct llog_rec_hdr *rec, void *data)
-{
- struct llog_fill_rec_data *lfd = (struct llog_fill_rec_data *)data;
- struct llog_unlink_rec *lur = (struct llog_unlink_rec *)rec;
-
- lur->lur_oid = lfd->lfd_id;
- lur->lur_ogen = lfd->lfd_ogen;
-
- RETURN(0);
-}
-
-/* callback function of lov to fill setattr log record */
-static int mds_log_fill_setattr_rec(struct llog_rec_hdr *rec, void *data)
-{
- struct llog_fill_rec_data *lfd = (struct llog_fill_rec_data *)data;
- struct llog_setattr_rec *lsr = (struct llog_setattr_rec *)rec;
-
- lsr->lsr_oid = lfd->lfd_id;
- lsr->lsr_ogen = lfd->lfd_ogen;
-
- RETURN(0);
-}
-
static int mds_llog_origin_add(struct llog_ctxt *ctxt,
struct llog_rec_hdr *rec, struct lov_stripe_md *lsm,
- struct llog_cookie *logcookies, int numcookies,
- llog_fill_rec_cb_t fill_cb)
+ struct llog_cookie *logcookies, int numcookies)
{
struct obd_device *obd = ctxt->loc_obd;
struct obd_device *lov_obd = obd->u.mds.mds_osc_obd;
ENTRY;
lctxt = llog_get_context(lov_obd, ctxt->loc_idx);
- rc = llog_add(lctxt, rec, lsm, logcookies, numcookies, fill_cb);
+ rc = llog_add(lctxt, rec, lsm, logcookies, numcookies);
RETURN(rc);
}
ctxt = llog_get_context(obd, LLOG_MDS_OST_ORIG_CTXT);
rc = llog_add(ctxt, &lur->lur_hdr, lsm, logcookies,
- cookies_size / sizeof(struct llog_cookie),
- mds_log_fill_unlink_rec);
+ cookies_size / sizeof(struct llog_cookie));
obd_free_memmd(mds->mds_osc_exp, &lsm);
OBD_FREE(lur, sizeof(*lur));
/* write setattr log */
ctxt = llog_get_context(obd, LLOG_MDS_OST_ORIG_CTXT);
rc = llog_add(ctxt, &lsr->lsr_hdr, lsm, logcookies,
- cookies_size / sizeof(struct llog_cookie),
- mds_log_fill_setattr_rec);
+ cookies_size / sizeof(struct llog_cookie));
OBD_FREE(lsr, sizeof(*lsr));
out:
case OBD_IOC_SYNC: {
CDEBUG(D_HA, "syncing mds %s\n", obd->obd_name);
- rc = fsfilt_sync(obd, obd->u.mds.mds_sb);
+ rc = fsfilt_sync(obd, obd->u.obt.obt_sb);
RETURN(rc);
}
case OBD_IOC_SET_READONLY: {
void *handle;
- struct inode *inode = obd->u.mds.mds_sb->s_root->d_inode;
+ struct inode *inode = obd->u.obt.obt_sb->s_root->d_inode;
BDEVNAME_DECLARE_STORAGE(tmp);
CERROR("*** setting device %s read-only ***\n",
- ll_bdevname(obd->u.mds.mds_sb, tmp));
+ ll_bdevname(obd->u.obt.obt_sb, tmp));
handle = fsfilt_start(obd, inode, FSFILT_OP_MKNOD, NULL);
if (!IS_ERR(handle))
rc = fsfilt_commit(obd, inode, handle, 1);
CDEBUG(D_HA, "syncing mds %s\n", obd->obd_name);
- rc = fsfilt_sync(obd, obd->u.mds.mds_sb);
+ rc = fsfilt_sync(obd, obd->u.obt.obt_sb);
- lvfs_set_rdonly(lvfs_sbdev(obd->u.mds.mds_sb));
+ lvfs_set_rdonly(lvfs_sbdev(obd->u.obt.obt_sb));
RETURN(0);
}
obd->obd_name, uuid->uuid);
} else {
LASSERT(llog_get_context(obd, LLOG_MDS_OST_ORIG_CTXT) != NULL);
+
+ rc = obd_set_info(obd->u.mds.mds_osc_exp, strlen("mds_conn"),
+ "mds_conn", 0, uuid);
+ if (rc != 0)
+ RETURN(rc);
+
rc = mds_lov_start_synchronize(obd, uuid, 1);
+ lquota_recovery(quota_interface, obd);
}
RETURN(rc);
}
static int mds_create_objects(struct ptlrpc_request *req, int offset,
struct mds_update_record *rec,
struct mds_obd *mds, struct obd_device *obd,
- struct dentry *dchild, void **handle,
+ struct dentry *dchild, void **handle,
obd_id **ids)
{
struct inode *inode = dchild->d_inode;
/* Handles object creation, actual opening, and I/O epoch */
static int mds_finish_open(struct ptlrpc_request *req, struct dentry *dchild,
struct mds_body *body, int flags, void **handle,
- struct mds_update_record *rec,struct ldlm_reply *rep)
+ struct mds_update_record *rec,
+ struct ldlm_reply *rep)
{
struct mds_obd *mds = mds_req2mds(req);
struct obd_device *obd = req->rq_export->exp_obd;
int parent_mode = LCK_CR;
void *handle = NULL;
struct dentry_params dp;
- uid_t parent_uid = 0;
- gid_t parent_gid = 0;
+ unsigned int qcids[MAXQUOTAS] = {current->fsuid, current->fsgid};
+ unsigned int qpids[MAXQUOTAS] = {0, 0};
ENTRY;
+ CLASSERT(MAXQUOTAS < 4);
if (offset == 2) { /* intent */
rep = lustre_msg_buf(req->rq_repmsg, 0, sizeof (*rep));
body = lustre_msg_buf(req->rq_repmsg, 1, sizeof (*body));
cleanup:
rc = mds_finish_transno(mds, dchild ? dchild->d_inode : NULL, handle,
req, rc, rep ? rep->lock_policy_res1 : 0);
-
+
cleanup_no_trans:
switch (cleanup_phase) {
case 2:
} else if (created) {
mds_lock_new_child(obd, dchild->d_inode, NULL);
/* save uid/gid for quota acquire/release */
- parent_uid = dparent->d_inode->i_uid;
- parent_gid = dparent->d_inode->i_gid;
-
+ qpids[USRQUOTA] = dparent->d_inode->i_uid;
+ qpids[GRPQUOTA] = dparent->d_inode->i_gid;
}
l_dput(dchild);
case 1:
}
/* trigger dqacq on the owner of child and parent */
- mds_adjust_qunit(obd, current->fsuid, current->fsgid,
- parent_uid, parent_gid, rc);
+ lquota_adjust(quota_interface, obd, qcids, qpids, rc, FSFILT_OP_CREATE);
RETURN(rc);
}
struct llog_cookie *logcookies = NULL;
int lmm_size = 0, need_lock = 1;
int rc = 0, cleanup_phase = 0, err, locked = 0;
- uid_t child_uid = 0;
- gid_t child_gid = 0;
+ unsigned int qcids[MAXQUOTAS] = {0, 0};
+ unsigned int qpids[MAXQUOTAS] = {rec->ur_iattr.ia_uid,
+ rec->ur_iattr.ia_gid};
ENTRY;
LASSERT(offset == 0);
LASSERT(inode);
/* save uid/gid for quota acq/rel */
- child_uid = inode->i_uid;
- child_gid = inode->i_gid;
+ qcids[USRQUOTA] = inode->i_uid;
+ qcids[GRPQUOTA] = inode->i_gid;
if ((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)) &&
rec->ur_eadata != NULL) {
} else if (rec->ur_iattr.ia_valid) { /* setattr */
rc = fsfilt_setattr(obd, de, handle, &rec->ur_iattr, 0);
/* journal chown/chgrp in llog, just like unlink */
- if (rc == 0 && S_ISREG(inode->i_mode) &&
- rec->ur_iattr.ia_valid & (ATTR_UID | ATTR_GID) && lmm_size){
+ if (rc == 0 && lmm_size){
OBD_ALLOC(logcookies, mds->mds_max_cookiesize);
if (logcookies == NULL)
GOTO(cleanup, rc = -ENOMEM);
req->rq_status = rc;
/* trigger dqrel/dqacq for original owner and new owner */
- if (ia_valid & (ATTR_UID | ATTR_GID)) {
- mds_adjust_qunit(obd, rec->ur_iattr.ia_uid,
- rec->ur_iattr.ia_gid, 0, 0, rc);
- mds_adjust_qunit(obd, child_uid, child_gid, 0, 0, rc);
- }
+ if (ia_valid & (ATTR_UID | ATTR_GID))
+ lquota_adjust(quota_interface, obd, qcids, qpids, rc, FSFILT_OP_SETATTR);
+
return 0;
}
struct lustre_handle lockh;
int rc = 0, err, type = rec->ur_mode & S_IFMT, cleanup_phase = 0;
int created = 0;
- uid_t parent_uid = 0;
- gid_t parent_gid = 0;
+ unsigned int qcids[MAXQUOTAS] = {current->fsuid, current->fsgid};
+ unsigned int qpids[MAXQUOTAS] = {0, 0};
struct dentry_params dp;
ENTRY;
* See bug 2029 for more detail.*/
mds_lock_new_child(obd, dchild->d_inode, NULL);
/* save uid/gid of create inode and parent */
- parent_uid = dir->i_uid;
- parent_gid = dir->i_gid;
+ qpids[USRQUOTA] = dir->i_uid;
+ qpids[GRPQUOTA] = dir->i_gid;
} else {
rc = err;
}
req->rq_status = rc;
/* trigger dqacq on the owner of child and parent */
- mds_adjust_qunit(obd, current->fsuid, current->fsgid,
- parent_uid, parent_gid, rc);
+ lquota_adjust(quota_interface, obd, qcids, qpids, rc, FSFILT_OP_CREATE);
return 0;
}
struct lustre_handle parent_lockh, child_lockh, child_reuse_lockh;
void *handle = NULL;
int rc = 0, cleanup_phase = 0;
- uid_t child_uid = 0, parent_uid = 0;
- gid_t child_gid = 0, parent_gid = 0;
+ unsigned int qcids [MAXQUOTAS] = {0, 0};
+ unsigned int qpids [MAXQUOTAS] = {0, 0};
ENTRY;
LASSERT(offset == 0 || offset == 2);
}
/* save uid/gid for quota acquire/release */
- child_uid = child_inode->i_uid;
- child_gid = child_inode->i_gid;
- parent_uid = dparent->d_inode->i_uid;
- parent_gid = dparent->d_inode->i_gid;
+ qcids[USRQUOTA] = child_inode->i_uid;
+ qcids[GRPQUOTA] = child_inode->i_gid;
+ qpids[USRQUOTA] = dparent->d_inode->i_uid;
+ qpids[GRPQUOTA] = dparent->d_inode->i_gid;
cleanup_phase = 2; /* dchild has a lock */
req->rq_status = rc;
/* trigger dqrel on the owner of child and parent */
- mds_adjust_qunit(obd, child_uid, child_gid, parent_uid, parent_gid, rc);
+ lquota_adjust(quota_interface, obd, qcids, qpids, rc, FSFILT_OP_UNLINK);
return 0;
}
struct lov_mds_md *lmm = NULL;
int rc = 0, lock_count = 3, cleanup_phase = 0;
void *handle = NULL;
+ unsigned int qcids[MAXQUOTAS] = {0, 0};
+ unsigned int qpids[4] = {0, 0, 0, 0};
ENTRY;
LASSERT(offset == 0);
if (old_inode == new_inode)
GOTO(cleanup, rc = 0);
+ /* save uids/gids for qunit acquire/release */
+ qcids[USRQUOTA] = old_inode->i_uid;
+ qcids[GRPQUOTA] = old_inode->i_gid;
+ qpids[USRQUOTA] = de_tgtdir->d_inode->i_uid;
+ qpids[GRPQUOTA] = de_tgtdir->d_inode->i_gid;
+ qpids[2] = de_srcdir->d_inode->i_uid;
+ qpids[3] = de_srcdir->d_inode->i_gid;
+
/* if we are about to remove the target at first, pass the EA of
* that inode to client to perform and cleanup on OST */
body = lustre_msg_buf(req->rq_repmsg, 0, sizeof (*body));
LBUG();
}
req->rq_status = rc;
+
+ /* acquire/release qunit */
+ lquota_adjust(quota_interface, obd, qcids, qpids, rc, FSFILT_OP_RENAME);
return 0;
}
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
- *
- * lustre/mds/quota_context.c
- * Lustre Quota Context
- *
- * Copyright (c) 2001-2003 Cluster File Systems, Inc.
- * Author: Niu YaWei <niu@clusterfs.com>
- *
- * This file is part of Lustre, http://www.lustre.org.
- *
- * No redistribution or use is permitted outside of Cluster File Systems, Inc.
- *
- */
-#ifndef EXPORT_SYMTAB
-# define EXPORT_SYMTAB
-#endif
-
-#define DEBUG_SUBSYSTEM S_MDS
-
-#include <linux/version.h>
-#include <linux/fs.h>
-#include <asm/unistd.h>
-#include <linux/slab.h>
-#include <linux/quotaops.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/obd_class.h>
-#include <linux/lustre_quota.h>
-#include <linux/lustre_fsfilt.h>
-
-const unsigned long default_bunit_sz = 100 * 1024 * 1024; /* 100M bytes */
-const unsigned long default_btune_sz = 50 * 1024 * 1024; /* 50M bytes */
-const unsigned long default_iunit_sz = 5000; /* 5000 inodes */
-const unsigned long default_itune_sz = 2500; /* 2500 inodes */
-
-static inline int const
-qunit_hashfn(struct lustre_quota_ctxt *qctxt, struct qunit_data *qdata)
-{
- unsigned int id = qdata->qd_id;
- unsigned int type = qdata->qd_type;
-
- unsigned long tmp = ((unsigned long)qctxt >> L1_CACHE_SHIFT) ^ id;
- tmp = (tmp * (MAXQUOTAS - type)) % NR_DQHASH;
- return tmp;
-}
-
-static inline struct lustre_qunit *find_qunit(unsigned int hashent,
- struct lustre_quota_ctxt *qctxt,
- struct qunit_data *qdata)
-{
- struct list_head *pos;
- struct lustre_qunit *qunit = NULL;
- struct qunit_data *tmp;
-
- list_for_each(pos, qunit_hash + hashent) {
- qunit = list_entry(pos, struct lustre_qunit, lq_hash);
- tmp = &qunit->lq_data;
- if (qunit->lq_ctxt == qctxt &&
- qdata->qd_id == tmp->qd_id && qdata->qd_type == tmp->qd_type
- && qdata->qd_isblk == tmp->qd_isblk)
- return qunit;
- }
- return NULL;
-}
-
-/* check_cur_qunit - check the current usage of qunit.
- * @qctxt: quota context
- * @qdata: the type of quota unit to be checked
- *
- * return: 1 - need acquire qunit;
- * 2 - need release qunit;
- * 0 - need do nothing.
- * < 0 - error.
- */
-static int
-check_cur_qunit(struct obd_device *obd,
- struct lustre_quota_ctxt *qctxt, struct qunit_data *qdata)
-{
- struct super_block *sb = qctxt->lqc_sb;
- unsigned long qunit_sz, tune_sz;
- __u64 usage, limit;
- struct obd_quotactl *qctl = NULL;
- int ret = 0;
- ENTRY;
-
- if (!sb_any_quota_enabled(sb))
- RETURN(0);
-
- /* ignore root user */
- if (qdata->qd_id == 0 && qdata->qd_type == USRQUOTA)
- RETURN(0);
-
- OBD_ALLOC(qctl, sizeof(*qctl));
- if (qctl == NULL)
- RETURN(-ENOMEM);
-
- /* get fs quota usage & limit */
- qctl->qc_cmd = Q_GETQUOTA;
- qctl->qc_id = qdata->qd_id;
- qctl->qc_type = qdata->qd_type;
- ret = fsfilt_quotactl(obd, sb, qctl);
- if (ret) {
- if (ret == -ESRCH) /* no limit */
- ret = 0;
- else
- CERROR("can't get fs quota usage! (rc:%d)\n", ret);
- GOTO(out, ret);
- }
-
- if (qdata->qd_isblk) {
- usage = qctl->qc_dqblk.dqb_curspace;
- limit = qctl->qc_dqblk.dqb_bhardlimit;
- qunit_sz = qctxt->lqc_bunit_sz;
- tune_sz = qctxt->lqc_btune_sz;
-
- LASSERT(!(qunit_sz % QUOTABLOCK_SIZE));
- LASSERT(limit == MIN_QLIMIT
- || !((__u32) limit % toqb(qunit_sz)));
- limit = limit << QUOTABLOCK_BITS;
- } else {
- usage = qctl->qc_dqblk.dqb_curinodes;
- limit = qctl->qc_dqblk.dqb_ihardlimit;
- qunit_sz = qctxt->lqc_iunit_sz;
- tune_sz = qctxt->lqc_itune_sz;
- }
-
- /* if it's not first time to set quota, ignore the no quota limit
- * case */
- if (!limit)
- GOTO(out, ret = 0);
-
- /* we don't count the MIN_QLIMIT */
- if ((limit == MIN_QLIMIT && !qdata->qd_isblk) ||
- (toqb(limit) == MIN_QLIMIT && qdata->qd_isblk))
- limit = 0;
-
- LASSERT(qdata->qd_count == 0);
- if (limit <= usage + tune_sz) {
- while (qdata->qd_count + limit <= usage + tune_sz)
- qdata->qd_count += qunit_sz;
- ret = 1;
- } else if (limit > usage + qunit_sz + tune_sz) {
- while (limit - qdata->qd_count > usage + qunit_sz + tune_sz)
- qdata->qd_count += qunit_sz;
- ret = 2;
- }
- LASSERT(ret == 0 || qdata->qd_count);
-out:
- OBD_FREE(qctl, sizeof(*qctl));
- RETURN(ret);
-}
-
-/* must hold qctxt->lqc_qunit_lock */
-static struct lustre_qunit *dqacq_in_flight(struct lustre_quota_ctxt *qctxt,
- struct qunit_data *qdata)
-{
- unsigned int hashent = qunit_hashfn(qctxt, qdata);
- struct lustre_qunit *qunit = NULL;
- ENTRY;
-
- qunit = find_qunit(hashent, qctxt, qdata);
- RETURN(qunit);
-}
-
-static struct lustre_qunit *alloc_qunit(struct lustre_quota_ctxt *qctxt,
- struct qunit_data *qdata, int opc)
-{
- struct lustre_qunit *qunit = NULL;
- ENTRY;
-
- OBD_SLAB_ALLOC(qunit, qunit_cachep, SLAB_NOFS, sizeof(*qunit));
- if (qunit == NULL)
- RETURN(NULL);
-
- INIT_LIST_HEAD(&qunit->lq_hash);
- INIT_LIST_HEAD(&qunit->lq_waiters);
- atomic_set(&qunit->lq_refcnt, 1);
- qunit->lq_ctxt = qctxt;
- memcpy(&qunit->lq_data, qdata, sizeof(*qdata));
- qunit->lq_opc = opc;
-
- RETURN(qunit);
-}
-
-static inline void free_qunit(struct lustre_qunit *qunit)
-{
- OBD_SLAB_FREE(qunit, qunit_cachep, sizeof(*qunit));
-}
-
-static inline void qunit_get(struct lustre_qunit *qunit)
-{
- atomic_inc(&qunit->lq_refcnt);
-}
-
-static void qunit_put(struct lustre_qunit *qunit)
-{
- LASSERT(atomic_read(&qunit->lq_refcnt));
- if (atomic_dec_and_test(&qunit->lq_refcnt))
- free_qunit(qunit);
-}
-
-static void
-insert_qunit_nolock(struct lustre_quota_ctxt *qctxt, struct lustre_qunit *qunit)
-{
- struct list_head *head;
-
- head = qunit_hash + qunit_hashfn(qctxt, &qunit->lq_data);
- list_add(&qunit->lq_hash, head);
-}
-
-static void remove_qunit_nolock(struct lustre_qunit *qunit)
-{
- LASSERT(!list_empty(&qunit->lq_hash));
- list_del_init(&qunit->lq_hash);
-}
-
-struct qunit_waiter {
- struct list_head qw_entry;
- wait_queue_head_t qw_waitq;
- int qw_rc;
-};
-
-#define QDATA_DEBUG(qd, fmt, arg...) \
- CDEBUG(D_QUOTA, "id(%u) type(%u) count(%u) isblk(%u):" \
- fmt, qd->qd_id, qd->qd_type, qd->qd_count, qd->qd_isblk, \
- ## arg); \
-
-#define INC_QLIMIT(limit, count) (limit == MIN_QLIMIT) ? \
- (limit = count) : (limit += count)
-
-static int
-dqacq_completion(struct obd_device *obd,
- struct lustre_quota_ctxt *qctxt,
- struct qunit_data *qdata, int rc, int opc)
-{
- struct lustre_qunit *qunit = NULL;
- struct super_block *sb = qctxt->lqc_sb;
- unsigned long qunit_sz;
- struct list_head *pos, *tmp;
- int err = 0;
- ENTRY;
-
- LASSERT(qdata);
- qunit_sz =
- (qdata->qd_isblk) ? qctxt->lqc_bunit_sz : qctxt->lqc_iunit_sz;
- LASSERT(!(qdata->qd_count % qunit_sz));
-
- /* update local operational quota file */
- if (rc == 0) {
- __u32 count = QUSG(qdata->qd_count, qdata->qd_isblk);
- struct obd_quotactl *qctl = NULL;
-
- OBD_ALLOC(qctl, sizeof(*qctl));
- if (qctl == NULL)
- GOTO(out, err = -ENOMEM);
-
- /* acq/rel qunit for specified uid/gid is serialized,
- * so there is no race between get fs quota limit and
- * set fs quota limit */
- qctl->qc_cmd = Q_GETQUOTA;
- qctl->qc_id = qdata->qd_id;
- qctl->qc_type = qdata->qd_type;
- err = fsfilt_quotactl(obd, sb, qctl);
- if (err) {
- CERROR("error get quota fs limit! (rc:%d)\n", err);
- GOTO(out_mem, err);
- }
-
- switch (opc) {
- case QUOTA_DQACQ:
- if (qdata->qd_isblk) {
- qctl->qc_dqblk.dqb_valid = QIF_BLIMITS;
- INC_QLIMIT(qctl->qc_dqblk.dqb_bhardlimit,
- count);
- } else {
- qctl->qc_dqblk.dqb_valid = QIF_ILIMITS;
- INC_QLIMIT(qctl->qc_dqblk.dqb_ihardlimit,
- count);
- }
- break;
- case QUOTA_DQREL:
- if (qdata->qd_isblk) {
- LASSERT(count < qctl->qc_dqblk.dqb_bhardlimit);
- qctl->qc_dqblk.dqb_valid = QIF_BLIMITS;
- qctl->qc_dqblk.dqb_bhardlimit -= count;
- } else {
- LASSERT(count < qctl->qc_dqblk.dqb_ihardlimit);
- qctl->qc_dqblk.dqb_valid = QIF_ILIMITS;
- qctl->qc_dqblk.dqb_ihardlimit -= count;
- }
- break;
- default:
- LBUG();
- break;
- }
-
- /* clear quota limit */
- if (count == 0) {
- if (qdata->qd_isblk)
- qctl->qc_dqblk.dqb_bhardlimit = 0;
- else
- qctl->qc_dqblk.dqb_ihardlimit = 0;
- }
-
- qctl->qc_cmd = Q_SETQUOTA;
- err = fsfilt_quotactl(obd, sb, qctl);
- if (err)
- CERROR("error set quota fs limit! (rc:%d)\n", err);
-
- QDATA_DEBUG(qdata, "%s completion\n",
- opc == QUOTA_DQACQ ? "DQACQ" : "DQREL");
-out_mem:
- OBD_FREE(qctl, sizeof(*qctl));
- } else if (rc == -EDQUOT) {
- CWARN("acquire qunit got EDQUOT\n");
- } else {
- CERROR("acquire qunit got error! (rc:%d)\n", rc);
- }
-out:
- /* remove the qunit from hash */
- spin_lock(&qunit_hash_lock);
-
- qunit = dqacq_in_flight(qctxt, qdata);
-
- LASSERT(qunit);
- LASSERT(opc == qunit->lq_opc);
- remove_qunit_nolock(qunit);
-
- /* wake up all waiters */
- list_for_each_safe(pos, tmp, &qunit->lq_waiters) {
- struct qunit_waiter *qw = list_entry(pos, struct qunit_waiter,
- qw_entry);
- list_del_init(&qw->qw_entry);
- qw->qw_rc = rc;
- wake_up(&qw->qw_waitq);
- }
-
- spin_unlock(&qunit_hash_lock);
-
- qunit_put(qunit);
- RETURN(err);
-}
-
-struct dqacq_async_args {
- struct lustre_quota_ctxt *aa_ctxt;
- struct lustre_qunit *aa_qunit;
-};
-
-static int dqacq_interpret(struct ptlrpc_request *req, void *data, int rc)
-{
- struct dqacq_async_args *aa = (struct dqacq_async_args *)data;
- struct lustre_quota_ctxt *qctxt = aa->aa_ctxt;
- struct lustre_qunit *qunit = aa->aa_qunit;
- struct obd_device *obd = req->rq_import->imp_obd;
- struct qunit_data *qdata = NULL;
- ENTRY;
-
- qdata = lustre_swab_repbuf(req, 0, sizeof(*qdata), lustre_swab_qdata);
- if (rc == 0 && qdata == NULL)
- RETURN(-EPROTO);
-
- LASSERT(qdata->qd_id == qunit->lq_data.qd_id &&
- qdata->qd_type == qunit->lq_data.qd_type &&
- (qdata->qd_count == qunit->lq_data.qd_count ||
- qdata->qd_count == 0));
-
- QDATA_DEBUG(qdata, "%s interpret rc(%d).\n",
- req->rq_reqmsg->opc == QUOTA_DQACQ ? "DQACQ" : "DQREL", rc);
-
- rc = dqacq_completion(obd, qctxt, qdata, rc, req->rq_reqmsg->opc);
-
- RETURN(rc);
-}
-
-static int got_qunit(struct qunit_waiter *waiter)
-{
- int rc = 0;
- ENTRY;
- spin_lock(&qunit_hash_lock);
- rc = list_empty(&waiter->qw_entry);
- spin_unlock(&qunit_hash_lock);
- RETURN(rc);
-}
-
-static int
-schedule_dqacq(struct obd_device *obd,
- struct lustre_quota_ctxt *qctxt,
- struct qunit_data *qdata, int opc, int wait)
-{
- struct lustre_qunit *qunit = NULL;
- struct qunit_waiter qw;
- struct l_wait_info lwi = { 0 };
- int rc = 0;
- ENTRY;
-
- INIT_LIST_HEAD(&qw.qw_entry);
- init_waitqueue_head(&qw.qw_waitq);
- qw.qw_rc = 0;
-
- spin_lock(&qunit_hash_lock);
-
- qunit = dqacq_in_flight(qctxt, qdata);
- if (qunit && wait) {
- list_add_tail(&qw.qw_entry, &qunit->lq_waiters);
- spin_unlock(&qunit_hash_lock);
- goto wait_completion;
- } else if (qunit && !wait) {
- qunit = NULL;
- } else if (!qunit && (qunit = alloc_qunit(qctxt, qdata, opc)) != NULL)
- insert_qunit_nolock(qctxt, qunit);
-
- spin_unlock(&qunit_hash_lock);
-
- if (qunit) {
- struct ptlrpc_request *req;
- struct qunit_data *reqdata;
- struct dqacq_async_args *aa;
- int size = sizeof(*reqdata);
-
- /* master is going to dqacq/dqrel from itself */
- if (qctxt->lqc_handler) {
- int rc2;
- QDATA_DEBUG(qdata, "local %s.\n",
- opc == QUOTA_DQACQ ? "DQACQ" : "DQREL");
- rc = qctxt->lqc_handler(obd, qdata, opc);
- rc2 = dqacq_completion(obd, qctxt, qdata, rc, opc);
- RETURN((rc && rc != -EDQUOT) ? rc : rc2);
- }
-
- /* build dqacq/dqrel request */
- LASSERT(qctxt->lqc_import);
- req = ptlrpc_prep_req(qctxt->lqc_import, opc, 1, &size, NULL);
- if (!req) {
- dqacq_completion(obd, qctxt, qdata, -ENOMEM, opc);
- RETURN(-ENOMEM);
- }
-
- reqdata = lustre_msg_buf(req->rq_reqmsg, 0, sizeof(*reqdata));
- memcpy(reqdata, qdata, sizeof(*reqdata));
- size = sizeof(*reqdata);
- req->rq_replen = lustre_msg_size(1, &size);
-
- LASSERT(sizeof(*aa) <= sizeof(req->rq_async_args));
- aa = (struct dqacq_async_args *)&req->rq_async_args;
- aa->aa_ctxt = qctxt;
- aa->aa_qunit = qunit;
-
- req->rq_interpret_reply = dqacq_interpret;
- ptlrpcd_add_req(req);
-
- QDATA_DEBUG(qdata, "%s scheduled.\n",
- opc == QUOTA_DQACQ ? "DQACQ" : "DQREL");
- }
-wait_completion:
- if (wait && qunit) {
- struct qunit_data *p = &qunit->lq_data;
- QDATA_DEBUG(p, "wait for dqacq.\n");
-
- l_wait_event(qw.qw_waitq, got_qunit(&qw), &lwi);
- if (qw.qw_rc == 0)
- rc = -EAGAIN;
-
- CDEBUG(D_QUOTA, "wait dqacq done. (rc:%d)\n", qw.qw_rc);
- }
- RETURN(rc);
-}
-
-int
-qctxt_adjust_qunit(struct obd_device *obd, struct lustre_quota_ctxt *qctxt,
- uid_t uid, gid_t gid, __u32 isblk)
-{
- int ret, rc = 0, i = USRQUOTA;
- struct qunit_data qdata[MAXQUOTAS];
- ENTRY;
-
- if (!sb_any_quota_enabled(qctxt->lqc_sb))
- RETURN(0);
-
- qdata[USRQUOTA].qd_id = uid;
- qdata[USRQUOTA].qd_type = USRQUOTA;
- qdata[USRQUOTA].qd_isblk = isblk;
- qdata[USRQUOTA].qd_count = 0;
- qdata[GRPQUOTA].qd_id = gid;
- qdata[GRPQUOTA].qd_type = GRPQUOTA;
- qdata[GRPQUOTA].qd_isblk = isblk;
- qdata[GRPQUOTA].qd_count = 0;
-
-next:
- ret = check_cur_qunit(obd, qctxt, &qdata[i]);
- if (ret > 0) {
- int opc;
- /* need acquire or release */
- opc = ret == 1 ? QUOTA_DQACQ : QUOTA_DQREL;
- ret = schedule_dqacq(obd, qctxt, &qdata[i], opc, 0);
- if (!rc)
- rc = ret;
- }
- if (++i < MAXQUOTAS)
- goto next;
-
- RETURN(rc);
-}
-EXPORT_SYMBOL(qctxt_adjust_qunit);
-
-int
-qctxt_wait_on_dqacq(struct obd_device *obd, struct lustre_quota_ctxt *qctxt,
- uid_t uid, gid_t gid, __u32 isblk)
-{
- struct qunit_data qdata[MAXQUOTAS];
- int i = USRQUOTA, ret, rc = -EAGAIN;
- ENTRY;
-
- if (!sb_any_quota_enabled(qctxt->lqc_sb))
- RETURN(0);
-
- qdata[USRQUOTA].qd_id = uid;
- qdata[USRQUOTA].qd_type = USRQUOTA;
- qdata[USRQUOTA].qd_isblk = isblk;
- qdata[USRQUOTA].qd_count = 0;
- qdata[GRPQUOTA].qd_id = gid;
- qdata[GRPQUOTA].qd_type = GRPQUOTA;
- qdata[GRPQUOTA].qd_isblk = isblk;
- qdata[GRPQUOTA].qd_count = 0;
-
-next:
- ret = check_cur_qunit(obd, qctxt, &qdata[i]);
- if (ret > 0)
- rc = schedule_dqacq(obd, qctxt, &qdata[i], QUOTA_DQACQ, 1);
-
- if (++i < MAXQUOTAS)
- goto next;
-
- RETURN(rc);
-}
-EXPORT_SYMBOL(qctxt_wait_on_dqacq);
-
-int
-qctxt_init(struct lustre_quota_ctxt *qctxt, struct super_block *sb,
- dqacq_handler_t handler)
-{
- int rc = 0;
- ENTRY;
-
- rc = ptlrpcd_addref();
- if (rc)
- RETURN(rc);
-
- qctxt->lqc_handler = handler;
- qctxt->lqc_sb = sb;
- qctxt->lqc_import = NULL;
- qctxt->lqc_flags = 0;
- qctxt->lqc_bunit_sz = default_bunit_sz;
- qctxt->lqc_btune_sz = default_btune_sz;
- qctxt->lqc_iunit_sz = default_iunit_sz;
- qctxt->lqc_itune_sz = default_itune_sz;
-
- RETURN(0);
-}
-EXPORT_SYMBOL(qctxt_init);
-
-void qctxt_cleanup(struct lustre_quota_ctxt *qctxt, int force)
-{
- struct list_head *pos, *tmp;
- struct lustre_qunit *qunit;
- int i;
- ENTRY;
-
- ptlrpcd_decref();
-
- spin_lock(&qunit_hash_lock);
-
- for (i = 0; i < NR_DQHASH; i++) {
- list_for_each_safe(pos, tmp, &qunit_hash[i]) {
- qunit = list_entry(pos, struct lustre_qunit, lq_hash);
- LASSERT(qunit->lq_ctxt != qctxt);
- }
- }
-
- spin_unlock(&qunit_hash_lock);
- EXIT;
-}
-EXPORT_SYMBOL(qctxt_cleanup);
#include <linux/obd_ost.h>
#include <linux/obd_class.h>
#include <linux/lprocfs_status.h>
-#include <linux/lustre_quota.h>
extern struct list_head obd_types;
static spinlock_t obd_types_lock = SPIN_LOCK_UNLOCKED;
EXPORT_SYMBOL(obdo_cachep);
kmem_cache_t *import_cachep = NULL;
-#ifdef HAVE_QUOTA_SUPPORT
-kmem_cache_t *qunit_cachep = NULL;
-struct list_head qunit_hash[NR_DQHASH];
-spinlock_t qunit_hash_lock = SPIN_LOCK_UNLOCKED;
-EXPORT_SYMBOL(qunit_cachep);
-EXPORT_SYMBOL(qunit_hash);
-EXPORT_SYMBOL(qunit_hash_lock);
-#endif
-
-
int (*ptlrpc_put_connection_superhack)(struct ptlrpc_connection *c);
void (*ptlrpc_abort_inflight_superhack)(struct obd_import *imp);
return NULL;
}
-static void obd_cleanup_qunit_cache(void)
-{
-#ifdef HAVE_QUOTA_SUPPORT
- int i;
- ENTRY;
-
- spin_lock(&qunit_hash_lock);
- for (i = 0; i < NR_DQHASH; i++)
- LASSERT(list_empty(qunit_hash + i));
- spin_unlock(&qunit_hash_lock);
-
- if (qunit_cachep) {
- LASSERTF(kmem_cache_destroy(qunit_cachep) == 0,
- "Cannot destroy ll_qunit_cache\n");
- qunit_cachep = NULL;
- }
- EXIT;
-#endif
-}
void obd_cleanup_caches(void)
{
"Cannot destory ll_import_cache\n");
import_cachep = NULL;
}
- obd_cleanup_qunit_cache();
EXIT;
}
-static int obd_init_qunit_cache(void)
-{
-
-#ifdef HAVE_QUOTA_SUPPORT
- int i;
- ENTRY;
-
- LASSERT(qunit_cachep == NULL);
- qunit_cachep = kmem_cache_create("ll_qunit_cache",
- sizeof(struct lustre_qunit),
- 0, 0, NULL, NULL);
- if (!qunit_cachep)
- RETURN(-ENOMEM);
-
- spin_lock(&qunit_hash_lock);
- for (i = 0; i < NR_DQHASH; i++)
- INIT_LIST_HEAD(qunit_hash + i);
- spin_unlock(&qunit_hash_lock);
-#endif
- RETURN(0);
-}
-
int obd_init_caches(void)
{
- int rc = 0;
ENTRY;
LASSERT(obdo_cachep == NULL);
if (!import_cachep)
GOTO(out, -ENOMEM);
- rc = obd_init_qunit_cache();
- if (rc)
- GOTO(out, rc);
-
RETURN(0);
out:
obd_cleanup_caches();
int llog_add(struct llog_ctxt *ctxt, struct llog_rec_hdr *rec,
struct lov_stripe_md *lsm, struct llog_cookie *logcookies,
- int numcookies, llog_fill_rec_cb_t fill_cb)
+ int numcookies)
{
int rc;
ENTRY;
CTXT_CHECK_OP(ctxt, add, -EOPNOTSUPP);
- rc = CTXTP(ctxt, add)(ctxt, rec, lsm, logcookies, numcookies, fill_cb);
+ rc = CTXTP(ctxt, add)(ctxt, rec, lsm, logcookies, numcookies);
RETURN(rc);
}
EXPORT_SYMBOL(llog_add);
/* add for obdfilter/sz and mds/unlink */
int llog_obd_origin_add(struct llog_ctxt *ctxt,
struct llog_rec_hdr *rec, struct lov_stripe_md *lsm,
- struct llog_cookie *logcookies, int numcookies,
- llog_fill_rec_cb_t fill_cb)
+ struct llog_cookie *logcookies, int numcookies)
{
struct llog_handle *cathandle;
int rc;
}
filter->fo_vfsmnt = mnt;
- filter->fo_sb = mnt->mnt_sb;
+ obd->u.obt.obt_sb = mnt->mnt_sb;
filter->fo_fstype = mnt->mnt_sb->s_type->name;
CDEBUG(D_SUPER, "%s: mnt = %p\n", filter->fo_fstype, mnt);
GOTO(err_post, rc);
}
- rc = filter_quota_setup(filter);
- if (rc) {
+ rc = lquota_setup(quota_interface, obd, lcfg);
+ if (rc)
GOTO(err_post, rc);
- }
if (obd->obd_recovering) {
LCONSOLE_WARN("OST %s now serving %s, but will be in recovery "
err_mntput:
unlock_kernel();
mntput(mnt);
- filter->fo_sb = 0;
+ obd->u.obt.obt_sb = 0;
lock_kernel();
err_ops:
fsfilt_put_ops(obd->obd_fsops);
unsigned long page;
int rc;
+ CLASSERT(offsetof(struct obd_device, u.obt) ==
+ offsetof(struct obd_device, u.filter.fo_obt));
+
if (!LUSTRE_CFG_BUFLEN(lcfg, 1) || !LUSTRE_CFG_BUFLEN(lcfg, 2))
RETURN(-EINVAL);
ping_evictor_stop();
- filter_quota_cleanup(filter);
+ lquota_cleanup(quota_interface, obd);
ldlm_namespace_free(obd->obd_namespace, obd->obd_force);
- if (filter->fo_sb == NULL)
+ if (obd->u.obt.obt_sb == NULL)
RETURN(0);
- save_dev = lvfs_sbdev(filter->fo_sb);
+ save_dev = lvfs_sbdev(obd->u.obt.obt_sb);
lprocfs_free_obd_stats(obd);
lprocfs_obd_cleanup(obd);
filter_post(obd);
- shrink_dcache_parent(filter->fo_sb->s_root);
+ shrink_dcache_parent(obd->u.obt.obt_sb->s_root);
- LL_DQUOT_OFF(filter->fo_sb);
+ LL_DQUOT_OFF(obd->u.obt.obt_sb);
if (atomic_read(&filter->fo_vfsmnt->mnt_count) > 1)
CERROR("%s: mount point %p busy, mnt_count: %d\n",
}
mntput(filter->fo_vfsmnt);
- //destroy_buffers(filter->fo_sb->s_dev);
- filter->fo_sb = NULL;
+ //destroy_buffers(obd->u.obt.obt_sb->s_dev);
+ obd->u.obt.obt_sb = NULL;
lvfs_clear_rdonly(save_dev);
rc = class_disconnect(exp);
ldlm_cancel_locks_for_export(exp);
- fsfilt_sync(obd, obd->u.filter.fo_sb);
+ fsfilt_sync(obd, obd->u.obt.obt_sb);
/* flush any remaining cancel messages out to the target */
ctxt = llog_get_context(obd, LLOG_MDS_OST_REPL_CTXT);
int filter_setattr_internal(struct obd_export *exp, struct dentry *dentry,
struct obdo *oa, struct obd_trans_info *oti)
{
+ unsigned int orig_ids[MAXQUOTAS] = {0, 0};
struct llog_cookie *fcc = NULL;
struct filter_obd *filter;
struct iattr iattr;
- uid_t orig_uid = 0;
- gid_t orig_gid = 0;
void *handle;
int rc, err;
ENTRY;
down(&dentry->d_inode->i_sem);
if (iattr.ia_valid & (ATTR_UID | ATTR_GID)) {
- orig_uid = dentry->d_inode->i_uid;
- orig_gid = dentry->d_inode->i_gid;
+ orig_ids[USRQUOTA] = dentry->d_inode->i_uid;
+ orig_ids[GRPQUOTA] = dentry->d_inode->i_gid;
handle = fsfilt_start_log(exp->exp_obd, dentry->d_inode,
FSFILT_OP_SETATTR, oti, 1);
} else {
up(&dentry->d_inode->i_sem);
/* trigger quota release */
- if (rc == 0 && iattr.ia_valid & (ATTR_SIZE | ATTR_UID | ATTR_GID)) {
- int rc2 = qctxt_adjust_qunit(exp->exp_obd, &filter->fo_quota_ctxt,
- oa->o_uid, oa->o_gid, 1);
- if (rc2)
- CERROR("error filter adjust qunit! (rc:%d)\n", rc2);
-
- /* after owner changed, release quota for the original owner */
- rc2 = qctxt_adjust_qunit(exp->exp_obd, &filter->fo_quota_ctxt,
- orig_uid, orig_gid, 1);
- if (rc2)
- CERROR("error filter adjust qunit! (rc:%d)\n", rc2);
+ if (iattr.ia_valid & (ATTR_SIZE | ATTR_UID | ATTR_GID)) {
+ unsigned int cur_ids[MAXQUOTAS] = {oa->o_uid, oa->o_gid};
+ int rc2= lquota_adjust(quota_interface, exp->exp_obd, cur_ids,
+ orig_ids, rc, FSFILT_OP_SETATTR);
+ CDEBUG(rc2 ? D_ERROR : D_QUOTA,
+ "filter adjust qunit. (rc:%d)\n", rc2);
}
return rc;
}
unsigned long max_age)
{
struct filter_obd *filter = &obd->u.filter;
- int blockbits = filter->fo_sb->s_blocksize_bits;
+ int blockbits = obd->u.obt.obt_sb->s_blocksize_bits;
int rc;
ENTRY;
* might be under-reporting if clients haven't announced their
* caches with brw recently */
spin_lock(&obd->obd_osfs_lock);
- rc = fsfilt_statfs(obd, filter->fo_sb, max_age);
+ rc = fsfilt_statfs(obd, obd->u.obt.obt_sb, max_age);
memcpy(osfs, &obd->obd_osfs, sizeof(*osfs));
spin_unlock(&obd->obd_osfs_lock);
/* set EROFS to state field if FS is mounted as RDONLY. The goal is to
* stop creating files on MDS if OST is not good shape to create
* objects.*/
- osfs->os_state = (filter->fo_sb->s_flags & MS_RDONLY) ? EROFS : 0;
+ osfs->os_state = (filter->fo_obt.obt_sb->s_flags & MS_RDONLY) ?
+ EROFS : 0;
RETURN(rc);
}
void *handle = NULL;
struct llog_cookie *fcc = NULL;
int rc, rc2, cleanup_phase = 0, have_prepared = 0;
+ unsigned int qcids[MAXQUOTAS] = {0, 0};
obd_gr group = 0;
ENTRY;
}
/* trigger quota release */
- if (rc == 0) {
- rc2 = qctxt_adjust_qunit(obd, &filter->fo_quota_ctxt,
- oa->o_uid, oa->o_gid, 1);
- if (rc2)
- CERROR("error filter adjust qunit! (rc:%d)\n", rc2);
- }
+ qcids[USRQUOTA] = oa->o_uid;
+ qcids[GRPQUOTA] = oa->o_gid;
+ rc2 = lquota_adjust(quota_interface, obd, qcids, NULL, rc,
+ FSFILT_OP_UNLINK);
+ CDEBUG(rc2 ? D_ERROR : D_QUOTA,
+ "filter adjust qunit! (rc:%d)\n", rc2);
RETURN(rc);
}
struct filter_obd *filter;
obd_gr group = oa->o_gr;
struct obd_device *obd;
- int rc;
+ int rc = 0;
ENTRY;
obd = exp->exp_obd;
rc = filter_statfs(obd, osfs, jiffies - HZ);
if (rc == 0 && osfs->os_bavail < (osfs->os_blocks >> 10)) {
CDEBUG(D_HA, "OST out of space! avail "LPU64"\n",
- osfs->os_bavail << filter->fo_sb->s_blocksize_bits);
+ osfs->os_bavail << filter->fo_obt.obt_sb->s_blocksize_bits);
rc = -ENOSPC;
}
/* an objid of zero is taken to mean "sync whole filesystem" */
if (!oa || !(oa->o_valid & OBD_MD_FLID)) {
- rc = fsfilt_sync(exp->exp_obd, filter->fo_sb);
+ rc = fsfilt_sync(exp->exp_obd, filter->fo_obt.obt_sb);
/* flush any remaining cancel messages out to the target */
ctxt = llog_get_context(exp->exp_obd, LLOG_MDS_OST_REPL_CTXT);
llog_sync(ctxt, exp);
memcmp(key, "blocksize", keylen) == 0) {
__u32 *blocksize = val;
*vallen = sizeof(*blocksize);
- *blocksize = obd->u.filter.fo_sb->s_blocksize;
+ *blocksize = obd->u.obt.obt_sb->s_blocksize;
RETURN(0);
}
memcmp(key, "blocksize_bits", keylen) == 0) {
__u32 *blocksize_bits = val;
*vallen = sizeof(*blocksize_bits);
- *blocksize_bits = obd->u.filter.fo_sb->s_blocksize_bits;
+ *blocksize_bits = obd->u.obt.obt_sb->s_blocksize_bits;
RETURN(0);
}
/* setup llog imports */
ctxt = llog_get_context(obd, LLOG_MDS_OST_REPL_CTXT);
rc = llog_receptor_accept(ctxt, exp->exp_imp_reverse);
-
- filter_quota_set_info(exp, obd);
+
+ lquota_setinfo(quota_interface, exp, obd);
RETURN(rc);
}
case OBD_IOC_SYNC: {
CDEBUG(D_HA, "syncing ost %s\n", obd->obd_name);
- rc = fsfilt_sync(obd, obd->u.filter.fo_sb);
+ rc = fsfilt_sync(obd, obd->u.obt.obt_sb);
RETURN(rc);
}
case OBD_IOC_SET_READONLY: {
void *handle;
- struct super_block *sb = obd->u.filter.fo_sb;
+ struct super_block *sb = obd->u.obt.obt_sb;
struct inode *inode = sb->s_root->d_inode;
BDEVNAME_DECLARE_STORAGE(tmp);
CERROR("*** setting device %s read-only ***\n",
rc = fsfilt_commit(obd, inode, handle, 1);
CDEBUG(D_HA, "syncing ost %s\n", obd->obd_name);
- rc = fsfilt_sync(obd, obd->u.filter.fo_sb);
+ rc = fsfilt_sync(obd, obd->u.obt.obt_sb);
- lvfs_set_rdonly(lvfs_sbdev(obd->u.filter.fo_sb));
+ lvfs_set_rdonly(lvfs_sbdev(obd->u.obt.obt_sb));
RETURN(0);
}
static int filter_health_check(struct obd_device *obd)
{
- struct filter_obd *filter = &obd->u.filter;
int rc = 0;
/*
* health_check to return 0 on healthy
* and 1 on unhealthy.
*/
- if(filter->fo_sb->s_flags & MS_RDONLY)
+ if(obd->u.obt.obt_sb->s_flags & MS_RDONLY)
rc = 1;
return rc;
.o_llog_init = filter_llog_init,
.o_llog_finish = filter_llog_finish,
.o_iocontrol = filter_iocontrol,
- .o_quotacheck = filter_quotacheck,
- .o_quotactl = filter_quotactl,
.o_health_check = filter_health_check,
};
.o_iocontrol = filter_iocontrol,
};
+quota_interface_t *quota_interface = NULL;
+extern quota_interface_t filter_quota_interface;
+
static int __init obdfilter_init(void)
{
struct lprocfs_static_vars lvars;
if (obdfilter_created_scratchpad == NULL)
return -ENOMEM;
+ quota_interface = PORTAL_SYMBOL_GET(filter_quota_interface);
+ init_obd_quota_ops(quota_interface, &filter_obd_ops);
+ init_obd_quota_ops(quota_interface, &filter_sanobd_ops);
+
rc = class_register_type(&filter_obd_ops, lvars.module_vars,
OBD_FILTER_DEVICENAME);
if (rc)
if (rc) {
class_unregister_type(OBD_FILTER_DEVICENAME);
out:
+ if (quota_interface)
+ PORTAL_SYMBOL_PUT(filter_quota_interface);
+
OBD_FREE(obdfilter_created_scratchpad,
OBDFILTER_CREATED_SCRATCHPAD_ENTRIES *
sizeof(*obdfilter_created_scratchpad));
- }
+ }
+
return rc;
}
static void __exit obdfilter_exit(void)
{
+ if (quota_interface)
+ PORTAL_SYMBOL_PUT(filter_quota_interface);
+
class_unregister_type(OBD_FILTER_SAN_DEVICENAME);
class_unregister_type(OBD_FILTER_DEVICENAME);
OBD_FREE(obdfilter_created_scratchpad,
#endif
/* Quota stuff */
-#ifdef HAVE_QUOTA_SUPPORT
-int filter_quota_setup(struct filter_obd *filter);
-void filter_quota_cleanup(struct filter_obd *filter);
-void filter_quota_set_info(struct obd_export *exp, struct obd_device *obd);
-int filter_quotacheck(struct obd_export *exp, struct obd_quotactl *oqctl);
-int filter_quotactl(struct obd_export *exp, struct obd_quotactl *oqctl);
-int filter_quota_enforcement(struct obd_device *obd,
- unsigned int fsuid, unsigned int fsgid,
- struct lvfs_ucred **ret_uc);
-int filter_get_quota_flag(struct obd_device *obd, struct obdo *oa);
-int filter_quota_check_master(struct obd_device *obd, struct inode *inode);
-
-#ifdef LPROCFS
-int lprocfs_filter_rd_bunit(char *page, char **start, off_t off,
- int count, int *eof, void *data);
-int lprocfs_filter_rd_iunit(char *page, char **start, off_t off,
- int count, int *eof, void *data);
-int lprocfs_filter_wr_bunit(struct file *file, const char *buffer,
- unsigned long count, void *data);
-int lprocfs_filter_wr_iunit(struct file *file, const char *buffer,
- unsigned long count, void *data);
-int lprocfs_filter_rd_btune(char *page, char **start, off_t off,
- int count, int *eof, void *data);
-int lprocfs_filter_rd_itune(char *page, char **start, off_t off,
- int count, int *eof, void *data);
-int lprocfs_filter_wr_btune(struct file *file, const char *buffer,
- unsigned long count, void *data);
-int lprocfs_filter_wr_itune(struct file *file, const char *buffer,
- unsigned long count, void *data);
-#endif /* LPROCFS */
-#else /* !HAVE_QUOTA_SUPPORT */
-static inline int filter_quota_setup(struct filter_obd *filter)
-{
- return 0;
-}
-static inline void filter_quota_cleanup(struct filter_obd *filter) {}
-static inline void filter_quota_set_info(struct obd_export *exp,
- struct obd_device *obd) {}
-static inline int filter_quotacheck(struct obd_export *exp,
- struct obd_quotactl *oqctl)
-{
- return -ENOTSUPP;
-}
-static inline int filter_quotactl(struct obd_export *exp,
- struct obd_quotactl *oqctl)
-{
- return -ENOTSUPP;
-}
-static inline int filter_quota_enforcement(struct obd_device *obd,
- unsigned int fsuid,
- unsigned int fsgid,
- struct lvfs_ucred **ret_uc)
-{
- return 0;
-}
-static inline int filter_get_quota_flag(struct obd_device *obd,
- struct obdo *oa)
-{
- return 0;
-}
-static inline int filter_quota_check_master(struct obd_device *obd,
- struct inode *inode)
-{
- return 0;
-}
-#endif /* HAVE_QUOTA_SUPPORT */
+extern quota_interface_t *quota_interface;
#endif /* _FILTER_INTERNAL_H */
obd_size filter_grant_space_left(struct obd_export *exp)
{
struct obd_device *obd = exp->exp_obd;
- int blockbits = obd->u.filter.fo_sb->s_blocksize_bits;
+ int blockbits = obd->u.obt.obt_sb->s_blocksize_bits;
obd_size tot_granted = obd->u.filter.fo_tot_granted, avail, left = 0;
int rc, statfs_done = 0;
if (time_before(obd->obd_osfs_age, jiffies - HZ)) {
restat:
- rc = fsfilt_statfs(obd, obd->u.filter.fo_sb, jiffies + 1);
+ rc = fsfilt_statfs(obd, obd->u.obt.obt_sb, jiffies + 1);
if (rc) /* N.B. statfs can't really fail */
RETURN(0);
statfs_done = 1;
{
struct obd_device *obd = exp->exp_obd;
struct filter_export_data *fed = &exp->exp_filter_data;
- int blockbits = obd->u.filter.fo_sb->s_blocksize_bits;
+ int blockbits = obd->u.obt.obt_sb->s_blocksize_bits;
__u64 grant = 0;
LASSERT_SPIN_LOCKED(&obd->obd_osfs_lock);
struct inode *inode)
{
struct filter_export_data *fed = &exp->exp_filter_data;
- int blocksize = exp->exp_obd->u.filter.fo_sb->s_blocksize;
+ int blocksize = exp->exp_obd->u.obt.obt_sb->s_blocksize;
unsigned long used = 0, ungranted = 0, using;
int i, rc = -ENOSPC, obj, n = 0, mask = D_CACHE;
/* Rough calc in case we don't refresh cached statfs data */
using = (used + ungranted + 1 ) >>
- exp->exp_obd->u.filter.fo_sb->s_blocksize_bits;
+ exp->exp_obd->u.obt.obt_sb->s_blocksize_bits;
if (exp->exp_obd->obd_osfs.os_bavail > using)
exp->exp_obd->obd_osfs.os_bavail -= using;
else
unsigned long *dr_blocks;
spinlock_t dr_lock;
unsigned long dr_start_time; /* jiffies */
+ unsigned int dr_ignore_quota:1;
struct filter_obd *dr_filter;
};
LASSERT(dreq->dr_npages > 0);
create = 1;
sem = &obd->u.filter.fo_alloc_lock;
+
+ lquota_enforce(quota_interface, obd, dreq->dr_ignore_quota);
}
remap:
rc = fsfilt_map_inode_pages(obd, inode, dreq->dr_pages,
* pre-dqacq in time or this user has exceeded quota limit, we
* have to wait for the completion of in flight dqacq/dqrel,
* then try again */
- if (filter_quota_check_master(obd, inode))
+ if (lquota_acquire(quota_interface, obd, inode->i_uid,
+ inode->i_gid))
goto remap;
}
unsigned long now = jiffies;
int i, err, cleanup_phase = 0;
struct obd_device *obd = exp->exp_obd;
- struct filter_obd *filter = &obd->u.filter;
- struct lvfs_ucred *uc = NULL;
void *wait_handle;
int total_size = 0;
+ unsigned int qcids[MAXQUOTAS] = {0, 0};
ENTRY;
LASSERT(oti != NULL);
fso.fso_bufcnt = obj->ioo_bufcnt;
inode = res->dentry->d_inode;
+ dreq->dr_ignore_quota = 0;
for (i = 0, lnb = res; i < obj->ioo_bufcnt; i++, lnb++) {
loff_t this_size;
this_size = lnb->offset + lnb->len;
if (this_size > iattr.ia_size)
iattr.ia_size = this_size;
+
+ /* if one page is a write-back page from client cache, or it's
+ * written by root, then mark the whole io request as ignore
+ * quota request */
+ if (lnb->flags & (OBD_BRW_FROM_GRANT | OBD_BRW_NOQUOTA))
+ dreq->dr_ignore_quota = 1;
}
- /* The client store the user credit information fsuid and fsgid
- * in oa->o_uid and oa->o_gid. In case of quota enabled, we use
- * them to build the lvfs_ucred so as to enforce oss quota check */
- rc = filter_quota_enforcement(obd, oa->o_uid, oa->o_gid, &uc);
- if (rc)
- GOTO(cleanup, rc);
-
- push_ctxt(&saved, &obd->obd_lvfs_ctxt, uc);
+ push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
cleanup_phase = 2;
down(&inode->i_sem);
else
obdo_from_inode(oa, inode, OBD_MD_FLUID | OBD_MD_FLGID);
- filter_get_quota_flag(obd, oa);
+ lquota_getflag(quota_interface, obd, oa);
fsfilt_check_slow(now, obd_timeout, "direct_io");
switch (cleanup_phase) {
case 2:
- pop_ctxt(&saved, &obd->obd_lvfs_ctxt, uc);
- if (uc)
- OBD_FREE(uc, sizeof(*uc));
+ pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
LASSERT(current->journal_info == NULL);
case 1:
filter_iobuf_put(dreq);
}
/* trigger quota pre-acquire */
- if (rc == 0) {
- err = qctxt_adjust_qunit(obd, &filter->fo_quota_ctxt,
- oa->o_uid, oa->o_gid, 1);
- if (err)
- CERROR("error filter ajust qunit! (rc:%d)\n", err);
- }
+ qcids[USRQUOTA] = oa->o_uid;
+ qcids[GRPQUOTA] = oa->o_gid;
+ err = lquota_adjust(quota_interface, obd, qcids, NULL, rc,
+ FSFILT_OP_CREATE);
+ CDEBUG(err ? D_ERROR : D_QUOTA,
+ "error filter adjust qunit! (rc:%d)\n", err);
+
RETURN(rc);
}
}
/* Callback for processing the unlink log record received from MDS by
- * llog_client_api.
- */
+ * llog_client_api. */
static int filter_recov_log_unlink_cb(struct llog_ctxt *ctxt,
struct llog_rec_hdr *rec,
struct llog_cookie *cookie)
}
/* Callback for processing the setattr log record received from MDS by
- * llog_client_api.
- */
+ * llog_client_api. */
static int filter_recov_log_setattr_cb(struct llog_ctxt *ctxt,
struct llog_rec_hdr *rec,
struct llog_cookie *cookie)
return count;
}
+#ifdef HAVE_QUOTA_SUPPORT
+static int lprocfs_filter_rd_bunit(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ LASSERT(obd != NULL);
+
+ return snprintf(page, count, "%lu\n",
+ obd->u.obt.obt_qctxt.lqc_bunit_sz);
+}
+
+static int lprocfs_filter_rd_iunit(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ LASSERT(obd != NULL);
+
+ return snprintf(page, count, "%lu\n",
+ obd->u.obt.obt_qctxt.lqc_iunit_sz);
+}
+
+static int lprocfs_filter_wr_bunit(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ int val, rc;
+ LASSERT(obd != NULL);
+
+ rc = lprocfs_write_helper(buffer, count, &val);
+ if (rc)
+ return rc;
+
+ if (val % QUOTABLOCK_SIZE ||
+ val <= obd->u.obt.obt_qctxt.lqc_btune_sz)
+ return -EINVAL;
+
+ obd->u.obt.obt_qctxt.lqc_bunit_sz = val;
+ return count;
+}
+
+static int lprocfs_filter_wr_iunit(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ int val, rc;
+ LASSERT(obd != NULL);
+
+ rc = lprocfs_write_helper(buffer, count, &val);
+ if (rc)
+ return rc;
+
+ if (val <= obd->u.obt.obt_qctxt.lqc_itune_sz)
+ return -EINVAL;
+
+ obd->u.obt.obt_qctxt.lqc_iunit_sz = val;
+ return count;
+}
+
+static int lprocfs_filter_rd_btune(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ LASSERT(obd != NULL);
+
+ return snprintf(page, count, "%lu\n",
+ obd->u.obt.obt_qctxt.lqc_btune_sz);
+}
+
+static int lprocfs_filter_rd_itune(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ LASSERT(obd != NULL);
+
+ return snprintf(page, count, "%lu\n",
+ obd->u.obt.obt_qctxt.lqc_itune_sz);
+}
+
+static int lprocfs_filter_wr_btune(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ int val, rc;
+ LASSERT(obd != NULL);
+
+ rc = lprocfs_write_helper(buffer, count, &val);
+ if (rc)
+ return rc;
+
+ if (val <= QUOTABLOCK_SIZE * MIN_QLIMIT || val % QUOTABLOCK_SIZE ||
+ val >= obd->u.obt.obt_qctxt.lqc_bunit_sz)
+ return -EINVAL;
+
+ obd->u.obt.obt_qctxt.lqc_btune_sz = val;
+ return count;
+}
+
+static int lprocfs_filter_wr_itune(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ int val, rc;
+ LASSERT(obd != NULL);
+
+ rc = lprocfs_write_helper(buffer, count, &val);
+ if (rc)
+ return rc;
+
+ if (val <= MIN_QLIMIT ||
+ val >= obd->u.obt.obt_qctxt.lqc_iunit_sz)
+ return -EINVAL;
+
+ obd->u.obt.obt_qctxt.lqc_itune_sz = val;
+ return count;
+}
+#endif
+
static struct lprocfs_vars lprocfs_obd_vars[] = {
{ "uuid", lprocfs_rd_uuid, 0, 0 },
{ "blocksize", lprocfs_rd_blksize, 0, 0 },
{ "quota_itune_sz", lprocfs_filter_rd_itune,
lprocfs_filter_wr_itune, 0},
#endif
-
{ 0 }
};
void oscc_init(struct obd_device *obd);
void osc_wake_cache_waiters(struct client_obd *cli);
-#ifdef HAVE_QUOTA_SUPPORT
-int osc_get_quota_flag(struct client_obd *cli, unsigned int uid,
- unsigned int gid);
-int osc_set_quota_flag(struct client_obd *cli,
- unsigned int uid, unsigned int gid,
- obd_flag valid, obd_flag flags);
-int osc_qinfo_cleanup(struct client_obd *cli);
-int osc_qinfo_init(void);
-void osc_qinfo_exit(void);
-int osc_quotacheck(struct obd_export *exp, struct obd_quotactl *oqctl);
-int osc_poll_quotacheck(struct obd_export *exp, struct if_quotacheck *qchk);
-int osc_quotactl(struct obd_export *exp, struct obd_quotactl *oqctl);
-#else /* !HAVE_QUOTA_SUPPORT */
-static inline int osc_get_quota_flag(struct client_obd *cli,
- unsigned int uid, unsigned int gid)
-{
- return QUOTA_OK;
-}
-static inline int osc_set_quota_flag(struct client_obd *cli,
- unsigned int uid, unsigned int gid,
- obd_flag valid, obd_flag flags)
-{
- return 0;
-}
-static inline int osc_qinfo_cleanup(struct client_obd *cli)
-{
- return 0;
-}
-static inline int osc_qinfo_init(void)
-{
- return 0;
-}
-static inline void osc_qinfo_exit(void) {}
-static inline int osc_quotacheck(struct obd_export *exp,
- struct obd_quotactl *oqctl)
-{
- return -ENOTSUPP;
-}
-static inline int osc_poll_quotacheck(struct obd_export *exp,
- struct if_quotacheck *qchk)
-{
- return -ENOTSUPP;
-}
-static inline int osc_quotactl(struct obd_export *exp,
- struct obd_quotactl *oqctl)
-{
- return -ENOTSUPP;
-}
-#endif /* HAVE_QUOTA_SUPPORT */
+
+/* Quota stuff */
+extern quota_interface_t *quota_interface;
#ifdef LPROCFS
int lproc_osc_attach_seqstat(struct obd_device *dev);
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
- *
- * Copyright (c) 2003 Cluster File Systems, Inc.
- *
- * No redistribution or use is permitted outside of Cluster File Systems, Inc.
- *
- */
-
-#ifndef EXPORT_SYMTAB
-# define EXPORT_SYMTAB
-#endif
-#define DEBUG_SUBSYSTEM S_OSC
-
-#ifdef __KERNEL__
-# include <linux/module.h>
-# include <linux/obd_ost.h>
-# include <linux/lustre_net.h>
-# include <linux/lustre_dlm.h>
-# include <linux/lustre_lib.h>
-# include <linux/lustre_compat25.h>
-# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
-# include <linux/workqueue.h>
-# include <linux/smp_lock.h>
-# else
-# include <linux/locks.h>
-# endif
-#else
-# include <liblustre.h>
-#endif
-
-#include <linux/obd.h>
-#include "osc_internal.h"
-
-struct osc_quota_info {
- struct list_head oqi_hash; /* hash list */
- struct client_obd *oqi_cli; /* osc obd */
- unsigned int oqi_id; /* uid/gid of a file */
- short oqi_type; /* quota type */
- unsigned long oqi_flag; /* flag, NO_QUOTA */
-};
-
-spinlock_t qinfo_list_lock = SPIN_LOCK_UNLOCKED;
-
-static struct list_head qinfo_hash[NR_DQHASH];
-/* SLAB cache for client quota context */
-kmem_cache_t *qinfo_cachep = NULL;
-
-static inline int const hashfn(struct client_obd *cli,
- unsigned long id,
- int type)
-{
- unsigned long tmp = ((unsigned long)cli>>6) ^ id;
- tmp = (tmp * (MAXQUOTAS - type)) % NR_DQHASH;
- return tmp;
-}
-
-static inline void insert_qinfo_hash(struct osc_quota_info *oqi)
-{
- struct list_head *head = qinfo_hash +
- hashfn(oqi->oqi_cli, oqi->oqi_id, oqi->oqi_type);
- list_add(&oqi->oqi_hash, head);
-}
-
-static inline void remove_qinfo_hash(struct osc_quota_info *oqi)
-{
- list_del_init(&oqi->oqi_hash);
-}
-
-static inline struct osc_quota_info *find_qinfo(struct client_obd *cli,
- unsigned int id, int type)
-{
- unsigned int hashent = hashfn(cli, id, type);
- struct list_head *head;
- struct osc_quota_info *oqi;
-
- for (head = qinfo_hash[hashent].next;
- head != qinfo_hash+hashent; head = head->next) {
- oqi = list_entry(head, struct osc_quota_info, oqi_hash);
- LASSERT(oqi->oqi_flag == NO_QUOTA);
- if (oqi->oqi_cli == cli &&
- oqi->oqi_id == id && oqi->oqi_type == type)
- return oqi;
- }
- return NULL;
-}
-
-static struct osc_quota_info *alloc_qinfo(struct client_obd *cli,
- unsigned int id, int type)
-{
- struct osc_quota_info *oqi;
- ENTRY;
-
- OBD_SLAB_ALLOC(oqi, qinfo_cachep, SLAB_KERNEL, sizeof(*oqi));
- if(!oqi)
- RETURN(NULL);
-
- INIT_LIST_HEAD(&oqi->oqi_hash);
- oqi->oqi_cli = cli;
- oqi->oqi_id = id;
- oqi->oqi_type = type;
-
- RETURN(oqi);
-}
-
-static void free_qinfo(struct osc_quota_info *oqi)
-{
- OBD_SLAB_FREE(oqi, qinfo_cachep, sizeof(*oqi));
-}
-
-int osc_get_quota_flag(struct client_obd *cli,
- unsigned int uid, unsigned int gid)
-{
- unsigned int id;
- int cnt, rc = QUOTA_OK;
- ENTRY;
-
- spin_lock(&qinfo_list_lock);
- for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
- struct osc_quota_info *oqi = NULL;
-
- id = (cnt == USRQUOTA) ? uid : gid;
- oqi = find_qinfo(cli, id, cnt);
- if (oqi) {
- rc = NO_QUOTA;
- break;
- }
- }
- spin_unlock(&qinfo_list_lock);
-
- RETURN(rc);
-}
-
-int osc_set_quota_flag(struct client_obd *cli,
- unsigned int uid, unsigned int gid,
- obd_flag valid, obd_flag flags)
-{
- unsigned int id;
- obd_flag noquota;
- int cnt, rc = 0;
- ENTRY;
-
- spin_lock(&qinfo_list_lock);
-
- for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
- struct osc_quota_info *oqi = NULL;
-
- if (!(valid & ((cnt == USRQUOTA) ?
- OBD_MD_FLUSRQUOTA : OBD_MD_FLGRPQUOTA)))
- continue;
-
- id = (cnt == USRQUOTA) ? uid : gid;
- noquota = (cnt == USRQUOTA) ?
- (flags & OBD_FL_NO_USRQUOTA) : (flags & OBD_FL_NO_GRPQUOTA);
-
- oqi = find_qinfo(cli, id, cnt);
-
- if (oqi && !noquota) {
- remove_qinfo_hash(oqi);
- free_qinfo(oqi);
- } else if (!oqi && noquota) {
- oqi = alloc_qinfo(cli, id, cnt);
- if (!oqi) {
- CERROR("not enough mem!\n");
- rc = -ENOMEM;
- break;
- }
- oqi->oqi_flag = NO_QUOTA;
- insert_qinfo_hash(oqi);
- }
- }
-
- spin_unlock(&qinfo_list_lock);
-
- RETURN(rc);
-}
-
-int osc_qinfo_cleanup(struct client_obd *cli)
-{
- struct osc_quota_info *oqi, *n;
- int i;
- ENTRY;
-
- spin_lock(&qinfo_list_lock);
- for (i = 0; i < NR_DQHASH; i++) {
- list_for_each_entry_safe(oqi, n, &qinfo_hash[i], oqi_hash) {
- if (oqi->oqi_cli != cli)
- continue;
- remove_qinfo_hash(oqi);
- free_qinfo(oqi);
- }
- }
- spin_unlock(&qinfo_list_lock);
-
- RETURN(0);
-}
-
-int osc_qinfo_init(void)
-{
- int i;
- ENTRY;
-
- LASSERT(qinfo_cachep == NULL);
- qinfo_cachep = kmem_cache_create("osc_quota_info",
- sizeof(struct osc_quota_info),
- 0, 0, NULL, NULL);
- if (!qinfo_cachep)
- RETURN(-ENOMEM);
-
- for (i = 0; i < NR_DQHASH; i++)
- INIT_LIST_HEAD(qinfo_hash + i);
-
- RETURN(0);
-}
-
-void osc_qinfo_exit(void)
-{
- struct osc_quota_info *oqi, *n;
- int i;
- ENTRY;
-
- spin_lock(&qinfo_list_lock);
- for (i = 0; i < NR_DQHASH; i++) {
- list_for_each_entry_safe(oqi, n, &qinfo_hash[i], oqi_hash) {
- remove_qinfo_hash(oqi);
- free_qinfo(oqi);
- }
- }
- spin_unlock(&qinfo_list_lock);
-
- LASSERTF(kmem_cache_destroy(qinfo_cachep) == 0,
- "couldn't destroy osc quota info slab\n");
-}
-
-int osc_quotacheck(struct obd_export *exp, struct obd_quotactl *oqctl)
-{
- struct client_obd *cli = &exp->exp_obd->u.cli;
- struct ptlrpc_request *req;
- struct obd_quotactl *body;
- int size = sizeof(*body);
- int rc;
- ENTRY;
-
- req = ptlrpc_prep_req(class_exp2cliimp(exp), OST_QUOTACHECK, 1, &size,
- NULL);
- if (!req)
- GOTO(out, rc = -ENOMEM);
-
- body = lustre_msg_buf(req->rq_reqmsg, 0, sizeof(*body));
- memcpy(body, oqctl, sizeof(*body));
-
- req->rq_replen = lustre_msg_size(0, NULL);
-
- spin_lock(&cli->cl_qchk_lock);
- cli->cl_qchk_stat = CL_QUOTACHECKING;
- spin_unlock(&cli->cl_qchk_lock);
-
- rc = ptlrpc_queue_wait(req);
- if (rc) {
- spin_lock(&cli->cl_qchk_lock);
- cli->cl_qchk_stat = rc;
- spin_unlock(&cli->cl_qchk_lock);
- }
- out:
- ptlrpc_req_finished(req);
- RETURN (rc);
-}
-
-int osc_poll_quotacheck(struct obd_export *exp,
- struct if_quotacheck *qchk)
-{
- struct client_obd *cli = &exp->exp_obd->u.cli;
- int stat;
- ENTRY;
-
- spin_lock(&cli->cl_qchk_lock);
- stat = cli->cl_qchk_stat;
- spin_unlock(&cli->cl_qchk_lock);
-
- qchk->stat = stat;
- if (stat == CL_QUOTACHECKING) {
- qchk->stat = -ENODATA;
- stat = 0;
- } else if (qchk->stat) {
- if (qchk->stat > CL_QUOTACHECKING)
- qchk->stat = stat = -EINTR;
-
- strncpy(qchk->obd_type, "obdfilter", 10);
- qchk->obd_uuid = cli->cl_import->imp_target_uuid;
- }
- RETURN(stat);
-}
-
-int osc_quotactl(struct obd_export *exp, struct obd_quotactl *oqctl)
-{
- struct ptlrpc_request *req;
- struct obd_quotactl *oqc;
- int size = sizeof(*oqctl);
- int rc;
- ENTRY;
-
- req = ptlrpc_prep_req(class_exp2cliimp(exp), OST_QUOTACTL, 1, &size,
- NULL);
- if (!req)
- GOTO(out, rc = -ENOMEM);
-
- memcpy(lustre_msg_buf(req->rq_reqmsg, 0, sizeof (*oqctl)), oqctl, size);
-
- req->rq_replen = lustre_msg_size(1, &size);
-
- rc = ptlrpc_queue_wait(req);
- if (!rc) {
- oqc = lustre_swab_repbuf(req, 0, sizeof (*oqc),
- lustre_swab_obd_quotactl);
- if (oqc == NULL) {
- CERROR ("Can't unpack mds_body\n");
- GOTO(out, rc = -EPROTO);
- }
-
- memcpy(oqctl, oqc, sizeof(*oqctl));
- }
-out:
- ptlrpc_req_finished(req);
- RETURN (rc);
-}
-
/* set/clear over quota flag for a uid/gid */
if (req->rq_reqmsg->opc == OST_WRITE &&
body->oa.o_valid & (OBD_MD_FLUSRQUOTA | OBD_MD_FLGRPQUOTA))
- osc_set_quota_flag(cli, body->oa.o_uid, body->oa.o_gid,
- body->oa.o_valid, body->oa.o_flags);
+ lquota_setdq(quota_interface, cli, body->oa.o_uid,
+ body->oa.o_gid, body->oa.o_valid,
+ body->oa.o_flags);
if (rc < 0)
RETURN(rc);
ops = oap->oap_caller_ops;
ops->ap_fill_obdo(oap->oap_caller_data, cmd, oa);
- if (osc_get_quota_flag(cli, oa->o_uid, oa->o_gid) == NO_QUOTA)
+ if (lquota_chkdq(quota_interface, cli, oa->o_uid, oa->o_gid) ==
+ NO_QUOTA)
rc = -EDQUOT;
obdo_free(oa);
RETURN(rc);
}
+
static int osc_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
void *karg, void *uarg)
{
data->ioc_offset);
GOTO(out, err);
case OBD_IOC_POLL_QUOTACHECK:
- err = osc_poll_quotacheck(exp, (struct if_quotacheck *)karg);
+ err = lquota_poll_check(quota_interface, exp,
+ (struct if_quotacheck *)karg);
GOTO(out, err);
default:
CDEBUG(D_INODE, "unrecognised ioctl %#x by %s\n",
spin_unlock(&oscc->oscc_lock);
/* free memory of osc quota cache */
- osc_qinfo_cleanup(cli);
+ lquota_cleanup(quota_interface, obd);
ptlrpc_free_rq_pool(cli->cl_rq_pool);
.o_import_event = osc_import_event,
.o_llog_init = osc_llog_init,
.o_llog_finish = osc_llog_finish,
- .o_quotacheck = osc_quotacheck,
- .o_quotactl = osc_quotactl,
};
#if defined(__KERNEL__) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
};
#endif
+static quota_interface_t *quota_interface = NULL;
+extern quota_interface_t osc_quota_interface;
+
int __init osc_init(void)
{
struct lprocfs_static_vars lvars;
lprocfs_init_vars(osc, &sanlvars);
#endif
+ quota_interface = PORTAL_SYMBOL_GET(osc_quota_interface);
+ lquota_init(quota_interface);
+ init_obd_quota_ops(quota_interface, &osc_obd_ops);
+
rc = class_register_type(&osc_obd_ops, lvars.module_vars,
LUSTRE_OSC_NAME);
- if (rc)
+ if (rc) {
+ if (quota_interface)
+ PORTAL_SYMBOL_PUT(osc_quota_interface);
RETURN(rc);
+ }
#if defined(__KERNEL__) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
rc = class_register_type(&sanosc_obd_ops, sanlvars.module_vars,
LUSTRE_SANOSC_NAME);
- if (rc)
+ if (rc) {
class_unregister_type(LUSTRE_OSC_NAME);
+ if (quota_interface)
+ PORTAL_SYMBOL_PUT(osc_quota_interface);
+ RETURN(rc);
+ }
#endif
- rc = osc_qinfo_init();
-
RETURN(rc);
}
#ifdef __KERNEL__
static void /*__exit*/ osc_exit(void)
{
- osc_qinfo_exit();
+ lquota_exit(quota_interface);
+ if (quota_interface)
+ PORTAL_SYMBOL_PUT(osc_quota_interface);
+
#if defined(__KERNEL__) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
class_unregister_type(LUSTRE_SANOSC_NAME);
#endif
RETURN(rc);
}
+static int ost_handle_quotactl(struct ptlrpc_request *req)
+{
+ struct obd_quotactl *oqctl, *repoqc;
+ int rc, size = sizeof(*repoqc);
+ ENTRY;
+
+ oqctl = lustre_swab_reqbuf(req, 0, sizeof(*oqctl),
+ lustre_swab_obd_quotactl);
+ if (oqctl == NULL)
+ GOTO(out, rc = -EPROTO);
+
+ rc = lustre_pack_reply(req, 1, &size, NULL);
+ if (rc)
+ GOTO(out, rc);
+
+ repoqc = lustre_msg_buf(req->rq_repmsg, 0, sizeof(*repoqc));
+
+ req->rq_status = obd_quotactl(req->rq_export, oqctl);
+ *repoqc = *oqctl;
+out:
+ RETURN(rc);
+}
+
+static int ost_handle_quotacheck(struct ptlrpc_request *req)
+{
+ struct obd_quotactl *oqctl;
+ int rc;
+ ENTRY;
+
+ oqctl = lustre_swab_reqbuf(req, 0, sizeof(*oqctl),
+ lustre_swab_obd_quotactl);
+ if (oqctl == NULL)
+ RETURN(-EPROTO);
+
+ rc = lustre_pack_reply(req, 0, NULL, NULL);
+ if (rc) {
+ CERROR("ost: out of memory while packing quotacheck reply\n");
+ RETURN(-ENOMEM);
+ }
+
+ req->rq_status = obd_quotacheck(req->rq_export, oqctl);
+ RETURN(0);
+}
+
static int ost_filter_recovery_request(struct ptlrpc_request *req,
struct obd_device *obd, int *process)
{
case OST_QUOTACHECK:
CDEBUG(D_INODE, "quotacheck\n");
OBD_FAIL_RETURN(OBD_FAIL_OST_QUOTACHECK_NET, 0);
- rc = ost_quotacheck(req);
+ rc = ost_handle_quotacheck(req);
break;
case OST_QUOTACTL:
CDEBUG(D_INODE, "quotactl\n");
OBD_FAIL_RETURN(OBD_FAIL_OST_QUOTACTL_NET, 0);
- rc = ost_quotactl(req);
+ rc = ost_handle_quotactl(req);
break;
case OBD_PING:
DEBUG_REQ(D_INODE, req, "ping");
.o_health_check = ost_health_check,
};
+
static int __init ost_init(void)
{
struct lprocfs_static_vars lvars;
+ int rc;
ENTRY;
lprocfs_init_vars(ost,&lvars);
- RETURN(class_register_type(&ost_obd_ops, lvars.module_vars,
- LUSTRE_OST_NAME));
+ rc = class_register_type(&ost_obd_ops, lvars.module_vars,
+ LUSTRE_OST_NAME);
+ RETURN(rc);
}
static void /*__exit*/ ost_exit(void)
struct ost_thread_local_cache *ost_tls(struct ptlrpc_request *r);
-#ifdef HAVE_QUOTA_SUPPORT
/* Quota stuff */
-int ost_quotacheck(struct ptlrpc_request *req);
-int ost_quotactl(struct ptlrpc_request *req);
-#else
-static inline int ost_quotacheck(struct ptlrpc_request *req)
-{
- req->rq_status = -ENOTSUPP;
- return -ENOTSUPP;
-}
-static inline int ost_quotactl(struct ptlrpc_request *req)
-{
- req->rq_status = -ENOTSUPP;
- return -ENOTSUPP;
-}
-#endif
+extern quota_interface_t *quota_interface;
#endif /* OST_INTERNAL_H */
ptlrpc-objs := $(ldlm_objs) $(ptlrpc_objs)
-ifeq ($(PATCHLEVEL),6)
-#ptlrpc-objs += @top_srcdir@/lustre/mds/quota_context.o
-endif
-
default: all
ldlm_%.c: @LUSTRE@/ldlm/ldlm_%.c
lgr->lgr_hdr.lrh_len = lgr->lgr_tail.lrt_len = sizeof(*lgr);
lgr->lgr_hdr.lrh_type = LLOG_GEN_REC;
lgr->lgr_gen = ctxt->loc_gen;
- rc = llog_add(ctxt, &lgr->lgr_hdr, NULL, NULL, 1, NULL);
+ rc = llog_add(ctxt, &lgr->lgr_hdr, NULL, NULL, 1);
OBD_FREE(lgr, sizeof(*lgr));
if (rc != 1)
RETURN(rc);
--- /dev/null
+.Xrefs
+config.log
+config.status
+configure
+Makefile
+.deps
+TAGS
+.*.cmd
+autoMakefile.in
+autoMakefile
+*.ko
+*.mod.c
+.*.o.flags
+.tmp_versions
+.depend
--- /dev/null
+MODULES := lquota
+MODULES += quotactl_test quotacheck_test
+
+lquota-objs := quota_check.o quota_context.o quota_ctl.o quota_interface.o
+lquota-objs += quota_master.o
+quotactl-objs := quotactl_test.o
+quotaccheck-objs := quotacheck_test.o
+
+@INCLUDE_RULES@
+
--- /dev/null
+# Copyright (C) 2005 Cluster File Systems, Inc.
+#
+# This code is issued under the GNU General Public License.
+# See the file COPYING in this distribution
+
+if LIBLUSTRE
+noinst_LIBRARIES = libquota.a
+libquota_a_SOURCES = quota_check.c quota_ctl.c quota_interface.c
+libquota_a_CPPFLAGS = $(LLCPPFLAGS)
+libquota_a_CFLAGS = $(LLCFLAGS)
+endif
+
+if MODULES
+modulefs_DATA = lquota$(KMODEXT)
+endif
+
+MOSTLYCLEANFILES := @MOSTLYCLEANFILES@
+DIST_SOURCES := $(lquota-objs:%.o=%.c) quota_internal.h
+DIST_SOURCES += quotactl_test.c quotacheck_test.c
--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * lustre/quota/quota_check.c
+ *
+ * Copyright (c) 2005 Cluster File Systems, Inc.
+ *
+ * This file is part of Lustre, http://www.lustre.org.
+ *
+ * No redistribution or use is permitted outside of Cluster File Systems, Inc.
+ *
+ */
+#ifndef EXPORT_SYMTAB
+# define EXPORT_SYMTAB
+#endif
+#define DEBUG_SUBSYSTEM S_MDS
+
+#ifdef __KERNEL__
+# include <linux/version.h>
+# include <linux/module.h>
+# include <linux/init.h>
+# include <linux/fs.h>
+# include <linux/jbd.h>
+# include <linux/ext3_fs.h>
+# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+# include <linux/smp_lock.h>
+# include <linux/buffer_head.h>
+# include <linux/workqueue.h>
+# include <linux/mount.h>
+# else
+# include <linux/locks.h>
+# endif
+#else /* __KERNEL__ */
+# include <liblustre.h>
+#endif
+
+#include <linux/obd_class.h>
+#include <linux/lustre_mds.h>
+#include <linux/lustre_dlm.h>
+#include <linux/lustre_cfg.h>
+#include <linux/obd_ost.h>
+#include <linux/lustre_fsfilt.h>
+#include <linux/lustre_quota.h>
+#include "quota_internal.h"
+
+#ifdef __KERNEL__
+static int target_quotacheck_callback(struct obd_export *exp,
+ struct obd_quotactl *oqctl)
+{
+ struct ptlrpc_request *req;
+ struct obd_quotactl *body;
+ int rc, size = sizeof(*oqctl);
+ ENTRY;
+
+ req = ptlrpc_prep_req(exp->exp_imp_reverse, OBD_QC_CALLBACK,
+ 1, &size, NULL);
+ if (!req)
+ RETURN(-ENOMEM);
+
+ body = lustre_msg_buf(req->rq_reqmsg, 0, sizeof(*body));
+ *body = *oqctl;
+
+ req->rq_replen = lustre_msg_size(0, NULL);
+
+ rc = ptlrpc_queue_wait(req);
+ ptlrpc_req_finished(req);
+
+ RETURN(rc);
+}
+
+static int target_quotacheck_thread(void *data)
+{
+ unsigned long flags;
+ struct quotacheck_thread_args *qta = data;
+ struct obd_export *exp;
+ struct obd_device *obd;
+ struct obd_quotactl *oqctl;
+ struct lvfs_run_ctxt saved;
+ int rc;
+
+ lock_kernel();
+ ptlrpc_daemonize();
+
+ SIGNAL_MASK_LOCK(current, flags);
+ sigfillset(¤t->blocked);
+ RECALC_SIGPENDING;
+ SIGNAL_MASK_UNLOCK(current, flags);
+
+ THREAD_NAME(cfs_curproc_comm(), CFS_CURPROC_COMM_MAX, "%s",
+ "quotacheck");
+ unlock_kernel();
+
+ exp = qta->qta_exp;
+ obd = exp->exp_obd;
+ oqctl = &qta->qta_oqctl;
+
+ push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+
+ rc = fsfilt_quotacheck(obd, qta->qta_sb, oqctl);
+ if (rc)
+ CERROR("%s: fsfilt_quotacheck: %d\n", obd->obd_name, rc);
+
+ pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+
+ rc = target_quotacheck_callback(exp, oqctl);
+
+ atomic_inc(qta->qta_sem);
+
+ OBD_FREE_PTR(qta);
+ return rc;
+}
+
+int target_quota_check(struct obd_export *exp, struct obd_quotactl *oqctl)
+{
+ struct obd_device *obd = exp->exp_obd;
+ struct obd_device_target *obt = &obd->u.obt;
+ struct quotacheck_thread_args *qta;
+ int rc = 0;
+ ENTRY;
+
+ if (!atomic_dec_and_test(&obt->obt_quotachecking)) {
+ CDEBUG(D_INFO, "other people are doing quotacheck\n");
+ GOTO(out, rc = -EBUSY);
+ }
+
+ OBD_ALLOC_PTR(qta);
+ if (!qta)
+ GOTO(out, rc = -ENOMEM);
+
+ qta->qta_exp = exp;
+ qta->qta_oqctl = *oqctl;
+ qta->qta_sb = obt->obt_sb;
+ qta->qta_sem = &obt->obt_quotachecking;
+
+ if (!strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME)) {
+ /* quota master */
+ rc = init_admin_quotafiles(obd, &qta->qta_oqctl);
+ if (rc) {
+ CERROR("init_admin_quotafiles failed: %d\n", rc);
+ OBD_FREE_PTR(qta);
+ GOTO(out, rc);
+ }
+ }
+
+ rc = kernel_thread(target_quotacheck_thread, qta, CLONE_VM|CLONE_FILES);
+ if (rc >= 0) {
+ CDEBUG(D_INFO, "%s: target_quotacheck_thread: %d\n",
+ obd->obd_name, rc);
+ RETURN(0);
+ }
+
+ CERROR("%s: error starting quotacheck_thread: %d\n",
+ obd->obd_name, rc);
+ OBD_FREE_PTR(qta);
+out:
+ atomic_inc(&obt->obt_quotachecking);
+ RETURN(rc);
+}
+
+#endif /* __KERNEL__ */
+
+int client_quota_check(struct obd_export *exp, struct obd_quotactl *oqctl)
+{
+ struct client_obd *cli = &exp->exp_obd->u.cli;
+ struct ptlrpc_request *req;
+ struct obd_quotactl *body;
+ int size = sizeof(*body), opc;
+ int rc;
+ ENTRY;
+
+ if (!strcmp(exp->exp_obd->obd_type->typ_name, LUSTRE_MDC_NAME))
+ opc = MDS_QUOTACHECK;
+ else if (!strcmp(exp->exp_obd->obd_type->typ_name, LUSTRE_OSC_NAME))
+ opc = OST_QUOTACHECK;
+ else
+ RETURN(-EINVAL);
+
+ req = ptlrpc_prep_req(class_exp2cliimp(exp), opc, 1, &size,
+ NULL);
+ if (!req)
+ GOTO(out, rc = -ENOMEM);
+
+ body = lustre_msg_buf(req->rq_reqmsg, 0, sizeof(*body));
+ *body = *oqctl;
+
+ req->rq_replen = lustre_msg_size(0, NULL);
+
+ /* the next poll will find -ENODATA, that means quotacheck is
+ * going on */
+ cli->cl_qchk_stat = -ENODATA;
+ rc = ptlrpc_queue_wait(req);
+ if (rc)
+ cli->cl_qchk_stat = rc;
+out:
+ ptlrpc_req_finished(req);
+ RETURN(rc);
+}
+
+int client_quota_poll_check(struct obd_export *exp, struct if_quotacheck *qchk)
+{
+ struct client_obd *cli = &exp->exp_obd->u.cli;
+ int rc;
+ ENTRY;
+
+ rc = cli->cl_qchk_stat;
+
+ /* the client is not the previous one */
+ if (rc == CL_NOT_QUOTACHECKED)
+ rc = -EINTR;
+
+ qchk->obd_uuid = cli->cl_import->imp_target_uuid;
+ if (strncmp(exp->exp_obd->obd_type->typ_name, LUSTRE_OSC_NAME,
+ strlen(LUSTRE_OSC_NAME)))
+ memcpy(qchk->obd_type, LUSTRE_FILTER_NAME,
+ strlen(LUSTRE_FILTER_NAME));
+ else if (strncmp(exp->exp_obd->obd_type->typ_name, LUSTRE_MDC_NAME,
+ strlen(LUSTRE_MDC_NAME)))
+ memcpy(qchk->obd_type, LUSTRE_MDS_NAME,
+ strlen(LUSTRE_MDS_NAME));
+
+ RETURN(rc);
+}
+
+int lov_quota_check(struct obd_export *exp, struct obd_quotactl *oqctl)
+{
+ struct obd_device *obd = class_exp2obd(exp);
+ struct lov_obd *lov = &obd->u.lov;
+ int i, rc = 0;
+ ENTRY;
+
+ for (i = 0; i < lov->desc.ld_tgt_count; i++) {
+ int err;
+
+ if (!lov->tgts[i].active) {
+ CERROR("lov idx %d inactive\n", i);
+ RETURN(-EIO);
+ }
+
+ err = obd_quotacheck(lov->tgts[i].ltd_exp, oqctl);
+ if (err && lov->tgts[i].active && !rc)
+ rc = err;
+ }
+
+ RETURN(rc);
+}
--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * lustre/quota/quota_context.c
+ * Lustre Quota Context
+ *
+ * Copyright (c) 2001-2005 Cluster File Systems, Inc.
+ * Author: Niu YaWei <niu@clusterfs.com>
+ *
+ * This file is part of Lustre, http://www.lustre.org.
+ *
+ * No redistribution or use is permitted outside of Cluster File Systems, Inc.
+ *
+ */
+#ifndef EXPORT_SYMTAB
+# define EXPORT_SYMTAB
+#endif
+
+#define DEBUG_SUBSYSTEM S_MDS
+
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <asm/unistd.h>
+#include <linux/slab.h>
+#include <linux/quotaops.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/obd_class.h>
+#include <linux/lustre_quota.h>
+#include <linux/lustre_fsfilt.h>
+#include "quota_internal.h"
+
+unsigned long default_bunit_sz = 100 * 1024 * 1024; /* 100M bytes */
+unsigned long default_btune_ratio = 50; /* 50 percentage */
+unsigned long default_iunit_sz = 5000; /* 5000 inodes */
+unsigned long default_itune_ratio = 50; /* 50 percentage */
+
+kmem_cache_t *qunit_cachep = NULL;
+struct list_head qunit_hash[NR_DQHASH];
+spinlock_t qunit_hash_lock = SPIN_LOCK_UNLOCKED;
+
+struct lustre_qunit {
+ struct list_head lq_hash; /* Hash list in memory */
+ atomic_t lq_refcnt; /* Use count */
+ struct lustre_quota_ctxt *lq_ctxt; /* Quota context this applies to */
+ struct qunit_data lq_data; /* See qunit_data */
+ unsigned int lq_opc; /* QUOTA_DQACQ, QUOTA_DQREL */
+ struct list_head lq_waiters; /* All write threads waiting for this qunit */
+};
+
+void qunit_cache_cleanup(void)
+{
+ int i;
+ ENTRY;
+
+ spin_lock(&qunit_hash_lock);
+ for (i = 0; i < NR_DQHASH; i++)
+ LASSERT(list_empty(qunit_hash + i));
+ spin_unlock(&qunit_hash_lock);
+
+ if (qunit_cachep) {
+ int rc;
+ rc = kmem_cache_destroy(qunit_cachep);
+ LASSERT(rc == 0);
+ qunit_cachep = NULL;
+ }
+ EXIT;
+}
+
+int qunit_cache_init(void)
+{
+ int i;
+ ENTRY;
+
+ LASSERT(qunit_cachep == NULL);
+ qunit_cachep = kmem_cache_create("ll_qunit_cache",
+ sizeof(struct lustre_qunit),
+ 0, 0, NULL, NULL);
+ if (!qunit_cachep)
+ RETURN(-ENOMEM);
+
+ spin_lock(&qunit_hash_lock);
+ for (i = 0; i < NR_DQHASH; i++)
+ INIT_LIST_HEAD(qunit_hash + i);
+ spin_unlock(&qunit_hash_lock);
+ RETURN(0);
+}
+
+static inline int const
+qunit_hashfn(struct lustre_quota_ctxt *qctxt, struct qunit_data *qdata)
+{
+ unsigned int id = qdata->qd_id;
+ unsigned int type = qdata->qd_type;
+
+ unsigned long tmp = ((unsigned long)qctxt >> L1_CACHE_SHIFT) ^ id;
+ tmp = (tmp * (MAXQUOTAS - type)) % NR_DQHASH;
+ return tmp;
+}
+
+/* caller must hold qunit_hash_lock */
+static inline struct lustre_qunit *find_qunit(unsigned int hashent,
+ struct lustre_quota_ctxt *qctxt,
+ struct qunit_data *qdata)
+{
+ struct lustre_qunit *qunit = NULL;
+ struct qunit_data *tmp;
+
+ LASSERT_SPIN_LOCKED(&qunit_hash_lock);
+ list_for_each_entry(qunit, qunit_hash + hashent, lq_hash) {
+ tmp = &qunit->lq_data;
+ if (qunit->lq_ctxt == qctxt &&
+ qdata->qd_id == tmp->qd_id && qdata->qd_type == tmp->qd_type
+ && qdata->qd_isblk == tmp->qd_isblk)
+ return qunit;
+ }
+ return NULL;
+}
+
+/* check_cur_qunit - check the current usage of qunit.
+ * @qctxt: quota context
+ * @qdata: the type of quota unit to be checked
+ *
+ * return: 1 - need acquire qunit;
+ * 2 - need release qunit;
+ * 0 - need do nothing.
+ * < 0 - error.
+ */
+static int
+check_cur_qunit(struct obd_device *obd,
+ struct lustre_quota_ctxt *qctxt, struct qunit_data *qdata)
+{
+ struct super_block *sb = qctxt->lqc_sb;
+ unsigned long qunit_sz, tune_sz;
+ __u64 usage, limit;
+ struct obd_quotactl *qctl;
+ int ret = 0;
+ ENTRY;
+
+ if (!sb_any_quota_enabled(sb))
+ RETURN(0);
+
+ /* ignore root user */
+ if (qdata->qd_id == 0 && qdata->qd_type == USRQUOTA)
+ RETURN(0);
+
+ OBD_ALLOC_PTR(qctl);
+ if (qctl == NULL)
+ RETURN(-ENOMEM);
+
+ /* get fs quota usage & limit */
+ qctl->qc_cmd = Q_GETQUOTA;
+ qctl->qc_id = qdata->qd_id;
+ qctl->qc_type = qdata->qd_type;
+ ret = fsfilt_quotactl(obd, sb, qctl);
+ if (ret) {
+ if (ret == -ESRCH) /* no limit */
+ ret = 0;
+ else
+ CERROR("can't get fs quota usage! (rc:%d)\n", ret);
+ GOTO(out, ret);
+ }
+
+ if (qdata->qd_isblk) {
+ usage = qctl->qc_dqblk.dqb_curspace;
+ limit = qctl->qc_dqblk.dqb_bhardlimit << QUOTABLOCK_BITS;
+ qunit_sz = qctxt->lqc_bunit_sz;
+ tune_sz = qctxt->lqc_btune_sz;
+
+ LASSERT(!(qunit_sz % QUOTABLOCK_SIZE));
+ } else {
+ usage = qctl->qc_dqblk.dqb_curinodes;
+ limit = qctl->qc_dqblk.dqb_ihardlimit;
+ qunit_sz = qctxt->lqc_iunit_sz;
+ tune_sz = qctxt->lqc_itune_sz;
+ }
+
+ /* ignore the no quota limit case */
+ if (!limit)
+ GOTO(out, ret = 0);
+
+ /* we don't count the MIN_QLIMIT */
+ if ((limit == MIN_QLIMIT && !qdata->qd_isblk) ||
+ (toqb(limit) == MIN_QLIMIT && qdata->qd_isblk))
+ limit = 0;
+
+ LASSERT(qdata->qd_count == 0);
+ if (limit <= usage + tune_sz) {
+ while (qdata->qd_count + limit <= usage + tune_sz)
+ qdata->qd_count += qunit_sz;
+ ret = 1;
+ } else if (limit > usage + qunit_sz + tune_sz) {
+ while (limit - qdata->qd_count > usage + qunit_sz + tune_sz)
+ qdata->qd_count += qunit_sz;
+ ret = 2;
+ }
+ LASSERT(ret == 0 || qdata->qd_count);
+ EXIT;
+out:
+ OBD_FREE_PTR(qctl);
+ return ret;
+}
+
+/* caller must hold qunit_hash_lock */
+static struct lustre_qunit *dqacq_in_flight(struct lustre_quota_ctxt *qctxt,
+ struct qunit_data *qdata)
+{
+ unsigned int hashent = qunit_hashfn(qctxt, qdata);
+ struct lustre_qunit *qunit;
+ ENTRY;
+
+ LASSERT_SPIN_LOCKED(&qunit_hash_lock);
+ qunit = find_qunit(hashent, qctxt, qdata);
+ RETURN(qunit);
+}
+
+static struct lustre_qunit *alloc_qunit(struct lustre_quota_ctxt *qctxt,
+ struct qunit_data *qdata, int opc)
+{
+ struct lustre_qunit *qunit = NULL;
+ ENTRY;
+
+ OBD_SLAB_ALLOC(qunit, qunit_cachep, SLAB_NOFS, sizeof(*qunit));
+ if (qunit == NULL)
+ RETURN(NULL);
+
+ INIT_LIST_HEAD(&qunit->lq_hash);
+ INIT_LIST_HEAD(&qunit->lq_waiters);
+ atomic_set(&qunit->lq_refcnt, 1);
+ qunit->lq_ctxt = qctxt;
+ memcpy(&qunit->lq_data, qdata, sizeof(*qdata));
+ qunit->lq_opc = opc;
+
+ RETURN(qunit);
+}
+
+static inline void free_qunit(struct lustre_qunit *qunit)
+{
+ OBD_SLAB_FREE(qunit, qunit_cachep, sizeof(*qunit));
+}
+
+static inline void qunit_get(struct lustre_qunit *qunit)
+{
+ atomic_inc(&qunit->lq_refcnt);
+}
+
+static void qunit_put(struct lustre_qunit *qunit)
+{
+ LASSERT(atomic_read(&qunit->lq_refcnt));
+ if (atomic_dec_and_test(&qunit->lq_refcnt))
+ free_qunit(qunit);
+}
+
+static void
+insert_qunit_nolock(struct lustre_quota_ctxt *qctxt, struct lustre_qunit *qunit)
+{
+ struct list_head *head;
+
+ LASSERT(list_empty(&qunit->lq_hash));
+ head = qunit_hash + qunit_hashfn(qctxt, &qunit->lq_data);
+ list_add(&qunit->lq_hash, head);
+}
+
+static void remove_qunit_nolock(struct lustre_qunit *qunit)
+{
+ LASSERT(!list_empty(&qunit->lq_hash));
+ list_del_init(&qunit->lq_hash);
+}
+
+struct qunit_waiter {
+ struct list_head qw_entry;
+ wait_queue_head_t qw_waitq;
+ int qw_rc;
+};
+
+#define QDATA_DEBUG(qd, fmt, arg...) \
+ CDEBUG(D_QUOTA, "id(%u) type(%u) count(%u) isblk(%u):" \
+ fmt, qd->qd_id, qd->qd_type, qd->qd_count, qd->qd_isblk, \
+ ## arg); \
+
+#define INC_QLIMIT(limit, count) (limit == MIN_QLIMIT) ? \
+ (limit = count) : (limit += count)
+
+
+/* FIXME check if this mds is the master of specified id */
+static int
+is_master(struct obd_device *obd, struct lustre_quota_ctxt *qctxt,
+ unsigned int id, int type)
+{
+ return qctxt->lqc_handler ? 1 : 0;
+}
+
+static int
+schedule_dqacq(struct obd_device *obd, struct lustre_quota_ctxt *qctxt,
+ struct qunit_data *qdata, int opc, int wait);
+
+static int
+dqacq_completion(struct obd_device *obd,
+ struct lustre_quota_ctxt *qctxt,
+ struct qunit_data *qdata, int rc, int opc)
+{
+ struct lustre_qunit *qunit = NULL;
+ struct super_block *sb = qctxt->lqc_sb;
+ unsigned long qunit_sz;
+ struct qunit_waiter *qw, *tmp;
+ int err = 0;
+ ENTRY;
+
+ LASSERT(qdata);
+ qunit_sz = qdata->qd_isblk ? qctxt->lqc_bunit_sz : qctxt->lqc_iunit_sz;
+ LASSERT(!(qdata->qd_count % qunit_sz));
+
+ /* update local operational quota file */
+ if (rc == 0) {
+ __u32 count = QUSG(qdata->qd_count, qdata->qd_isblk);
+ struct obd_quotactl *qctl;
+ __u64 *hardlimit;
+
+ OBD_ALLOC_PTR(qctl);
+ if (qctl == NULL)
+ GOTO(out, err = -ENOMEM);
+
+ /* acq/rel qunit for specified uid/gid is serialized,
+ * so there is no race between get fs quota limit and
+ * set fs quota limit */
+ qctl->qc_cmd = Q_GETQUOTA;
+ qctl->qc_id = qdata->qd_id;
+ qctl->qc_type = qdata->qd_type;
+ err = fsfilt_quotactl(obd, sb, qctl);
+ if (err) {
+ CERROR("error get quota fs limit! (rc:%d)\n", err);
+ GOTO(out_mem, err);
+ }
+
+ if (qdata->qd_isblk) {
+ qctl->qc_dqblk.dqb_valid = QIF_BLIMITS;
+ hardlimit = &qctl->qc_dqblk.dqb_bhardlimit;
+ } else {
+ qctl->qc_dqblk.dqb_valid = QIF_ILIMITS;
+ hardlimit = &qctl->qc_dqblk.dqb_ihardlimit;
+ }
+
+ switch (opc) {
+ case QUOTA_DQACQ:
+ INC_QLIMIT(*hardlimit, count);
+ break;
+ case QUOTA_DQREL:
+ LASSERT(count < *hardlimit);
+ *hardlimit -= count;
+ break;
+ default:
+ LBUG();
+ }
+
+ /* clear quota limit */
+ if (count == 0)
+ *hardlimit = 0;
+
+ qctl->qc_cmd = Q_SETQUOTA;
+ err = fsfilt_quotactl(obd, sb, qctl);
+ if (err)
+ CERROR("error set quota fs limit! (rc:%d)\n", err);
+
+ QDATA_DEBUG(qdata, "%s completion\n",
+ opc == QUOTA_DQACQ ? "DQACQ" : "DQREL");
+out_mem:
+ OBD_FREE_PTR(qctl);
+ } else if (rc == -EDQUOT) {
+ QDATA_DEBUG(qdata, "acquire qunit got EDQUOT.\n");
+ } else if (rc == -EBUSY) {
+ QDATA_DEBUG(qdata, "it's is recovering, got EBUSY.\n");
+ } else {
+ CERROR("acquire qunit got error! (rc:%d)\n", rc);
+ }
+out:
+ /* remove the qunit from hash */
+ spin_lock(&qunit_hash_lock);
+
+ qunit = dqacq_in_flight(qctxt, qdata);
+ /* this qunit has been removed by qctxt_cleanup() */
+ if (!qunit) {
+ spin_unlock(&qunit_hash_lock);
+ RETURN(err);
+ }
+
+ LASSERT(opc == qunit->lq_opc);
+ remove_qunit_nolock(qunit);
+
+ /* wake up all waiters */
+ list_for_each_entry_safe(qw, tmp, &qunit->lq_waiters, qw_entry) {
+ list_del_init(&qw->qw_entry);
+ qw->qw_rc = rc;
+ wake_up(&qw->qw_waitq);
+ }
+
+ spin_unlock(&qunit_hash_lock);
+
+ qunit_put(qunit);
+
+ /* don't reschedule in such cases:
+ * - acq/rel failure, but not for quota recovery.
+ * - local dqacq/dqrel.
+ * - local disk io failure.
+ */
+ if (err || (rc && rc != -EBUSY) ||
+ is_master(obd, qctxt, qdata->qd_id, qdata->qd_type))
+ RETURN(err);
+
+ /* reschedule another dqacq/dqrel if needed */
+ qdata->qd_count = 0;
+ rc = check_cur_qunit(obd, qctxt, qdata);
+ if (rc > 0) {
+ int opc;
+ opc = rc == 1 ? QUOTA_DQACQ : QUOTA_DQREL;
+ rc = schedule_dqacq(obd, qctxt, qdata, opc, 0);
+ QDATA_DEBUG(qdata, "reschedudle opc(%d) rc(%d)\n", opc, rc);
+ }
+ RETURN(err);
+}
+
+struct dqacq_async_args {
+ struct lustre_quota_ctxt *aa_ctxt;
+ struct lustre_qunit *aa_qunit;
+};
+
+static int dqacq_interpret(struct ptlrpc_request *req, void *data, int rc)
+{
+ struct dqacq_async_args *aa = (struct dqacq_async_args *)data;
+ struct lustre_quota_ctxt *qctxt = aa->aa_ctxt;
+ struct lustre_qunit *qunit = aa->aa_qunit;
+ struct obd_device *obd = req->rq_import->imp_obd;
+ struct qunit_data *qdata = NULL;
+ ENTRY;
+
+ qdata = lustre_swab_repbuf(req, 0, sizeof(*qdata), lustre_swab_qdata);
+ if (rc == 0 && qdata == NULL)
+ RETURN(-EPROTO);
+
+ LASSERT(qdata->qd_id == qunit->lq_data.qd_id &&
+ qdata->qd_type == qunit->lq_data.qd_type &&
+ (qdata->qd_count == qunit->lq_data.qd_count ||
+ qdata->qd_count == 0));
+
+ QDATA_DEBUG(qdata, "%s interpret rc(%d).\n",
+ req->rq_reqmsg->opc == QUOTA_DQACQ ? "DQACQ" : "DQREL", rc);
+
+ rc = dqacq_completion(obd, qctxt, qdata, rc, req->rq_reqmsg->opc);
+
+ RETURN(rc);
+}
+
+static int got_qunit(struct qunit_waiter *waiter)
+{
+ int rc = 0;
+ ENTRY;
+ spin_lock(&qunit_hash_lock);
+ rc = list_empty(&waiter->qw_entry);
+ spin_unlock(&qunit_hash_lock);
+ RETURN(rc);
+}
+
+static int
+schedule_dqacq(struct obd_device *obd,
+ struct lustre_quota_ctxt *qctxt,
+ struct qunit_data *qdata, int opc, int wait)
+{
+ struct lustre_qunit *qunit, *empty;
+ struct qunit_waiter qw;
+ struct l_wait_info lwi = { 0 };
+ struct ptlrpc_request *req;
+ struct qunit_data *reqdata;
+ struct dqacq_async_args *aa;
+ int size = sizeof(*reqdata);
+ int rc = 0;
+ ENTRY;
+
+ INIT_LIST_HEAD(&qw.qw_entry);
+ init_waitqueue_head(&qw.qw_waitq);
+ qw.qw_rc = 0;
+
+ if ((empty = alloc_qunit(qctxt, qdata, opc)) == NULL)
+ RETURN(-ENOMEM);
+
+ spin_lock(&qunit_hash_lock);
+
+ qunit = dqacq_in_flight(qctxt, qdata);
+ if (qunit) {
+ if (wait)
+ list_add_tail(&qw.qw_entry, &qunit->lq_waiters);
+ spin_unlock(&qunit_hash_lock);
+
+ free_qunit(empty);
+ goto wait_completion;
+ }
+ qunit = empty;
+ insert_qunit_nolock(qctxt, qunit);
+ if (wait)
+ list_add_tail(&qw.qw_entry, &qunit->lq_waiters);
+ spin_unlock(&qunit_hash_lock);
+
+ LASSERT(qunit);
+
+ /* master is going to dqacq/dqrel from itself */
+ if (is_master(obd, qctxt, qdata->qd_id, qdata->qd_type)) {
+ int rc2;
+ QDATA_DEBUG(qdata, "local %s.\n",
+ opc == QUOTA_DQACQ ? "DQACQ" : "DQREL");
+ rc = qctxt->lqc_handler(obd, qdata, opc);
+ rc2 = dqacq_completion(obd, qctxt, qdata, rc, opc);
+ RETURN((rc && rc != -EDQUOT) ? rc : rc2);
+ }
+
+ /* build dqacq/dqrel request */
+ LASSERT(qctxt->lqc_import);
+ req = ptlrpc_prep_req(qctxt->lqc_import, opc, 1, &size, NULL);
+ if (!req) {
+ dqacq_completion(obd, qctxt, qdata, -ENOMEM, opc);
+ RETURN(-ENOMEM);
+ }
+
+ reqdata = lustre_msg_buf(req->rq_reqmsg, 0, sizeof(*reqdata));
+ *reqdata = *qdata;
+ size = sizeof(*reqdata);
+ req->rq_replen = lustre_msg_size(1, &size);
+
+ CLASSERT(sizeof(*aa) <= sizeof(req->rq_async_args));
+ aa = (struct dqacq_async_args *)&req->rq_async_args;
+ aa->aa_ctxt = qctxt;
+ aa->aa_qunit = qunit;
+
+ req->rq_interpret_reply = dqacq_interpret;
+ ptlrpcd_add_req(req);
+
+ QDATA_DEBUG(qdata, "%s scheduled.\n",
+ opc == QUOTA_DQACQ ? "DQACQ" : "DQREL");
+wait_completion:
+ if (wait && qunit) {
+ struct qunit_data *p = &qunit->lq_data;
+ QDATA_DEBUG(p, "wait for dqacq.\n");
+
+ l_wait_event(qw.qw_waitq, got_qunit(&qw), &lwi);
+ if (qw.qw_rc == 0)
+ rc = -EAGAIN;
+
+ CDEBUG(D_QUOTA, "wait dqacq done. (rc:%d)\n", qw.qw_rc);
+ }
+ RETURN(rc);
+}
+
+int
+qctxt_adjust_qunit(struct obd_device *obd, struct lustre_quota_ctxt *qctxt,
+ uid_t uid, gid_t gid, __u32 isblk, int wait)
+{
+ int ret, rc = 0, i = USRQUOTA;
+ __u32 id[MAXQUOTAS] = { uid, gid };
+ struct qunit_data qdata[MAXQUOTAS];
+ ENTRY;
+
+ CLASSERT(MAXQUOTAS < 4);
+ if (!sb_any_quota_enabled(qctxt->lqc_sb))
+ RETURN(0);
+
+ for (i = 0; i < MAXQUOTAS; i++) {
+ qdata[i].qd_id = id[i];
+ qdata[i].qd_type = i;
+ qdata[i].qd_isblk = isblk;
+ qdata[i].qd_count = 0;
+
+ ret = check_cur_qunit(obd, qctxt, &qdata[i]);
+ if (ret > 0) {
+ int opc;
+ /* need acquire or release */
+ opc = ret == 1 ? QUOTA_DQACQ : QUOTA_DQREL;
+ ret = schedule_dqacq(obd, qctxt, &qdata[i], opc, wait);
+ if (!rc)
+ rc = ret;
+ }
+ }
+
+ RETURN(rc);
+}
+
+int
+qctxt_wait_pending_dqacq(struct lustre_quota_ctxt *qctxt, unsigned int id,
+ unsigned short type, int isblk)
+{
+ struct lustre_qunit *qunit = NULL;
+ struct qunit_waiter qw;
+ struct qunit_data qdata;
+ struct l_wait_info lwi = { 0 };
+ ENTRY;
+
+ INIT_LIST_HEAD(&qw.qw_entry);
+ init_waitqueue_head(&qw.qw_waitq);
+ qw.qw_rc = 0;
+
+ qdata.qd_id = id;
+ qdata.qd_type = type;
+ qdata.qd_isblk = isblk;
+ qdata.qd_count = 0;
+
+ spin_lock(&qunit_hash_lock);
+
+ qunit = dqacq_in_flight(qctxt, &qdata);
+ if (qunit)
+ list_add_tail(&qw.qw_entry, &qunit->lq_waiters);
+
+ spin_unlock(&qunit_hash_lock);
+
+ if (qunit) {
+ struct qunit_data *p = &qdata;
+ QDATA_DEBUG(p, "wait for dqacq completion.\n");
+ l_wait_event(qw.qw_waitq, got_qunit(&qw), &lwi);
+ QDATA_DEBUG(p, "wait dqacq done. (rc:%d)\n", qw.qw_rc);
+ }
+ RETURN(0);
+}
+
+int
+qctxt_init(struct lustre_quota_ctxt *qctxt, struct super_block *sb,
+ dqacq_handler_t handler)
+{
+ int rc = 0;
+ ENTRY;
+
+ rc = ptlrpcd_addref();
+ if (rc)
+ RETURN(rc);
+
+ qctxt->lqc_handler = handler;
+ qctxt->lqc_sb = sb;
+ qctxt->lqc_import = NULL;
+ qctxt->lqc_recovery = 0;
+ qctxt->lqc_bunit_sz = default_bunit_sz;
+ qctxt->lqc_btune_sz = default_bunit_sz / 100 * default_btune_ratio;
+ qctxt->lqc_iunit_sz = default_iunit_sz;
+ qctxt->lqc_itune_sz = default_iunit_sz * default_itune_ratio / 100;
+
+ RETURN(0);
+}
+
+void qctxt_cleanup(struct lustre_quota_ctxt *qctxt, int force)
+{
+ struct lustre_qunit *qunit, *tmp;
+ struct qunit_waiter *qw, *tmp2;
+ int i;
+ ENTRY;
+
+ spin_lock(&qunit_hash_lock);
+
+ for (i = 0; i < NR_DQHASH; i++) {
+ list_for_each_entry_safe(qunit, tmp, &qunit_hash[i], lq_hash) {
+ if (qunit->lq_ctxt != qctxt)
+ continue;
+
+ remove_qunit_nolock(qunit);
+ /* wake up all waiters */
+ list_for_each_entry_safe(qw, tmp2, &qunit->lq_waiters,
+ qw_entry) {
+ list_del_init(&qw->qw_entry);
+ qw->qw_rc = 0;
+ wake_up(&qw->qw_waitq);
+ }
+ qunit_put(qunit);
+ }
+ }
+
+ spin_unlock(&qunit_hash_lock);
+
+ ptlrpcd_decref();
+
+ EXIT;
+}
+
+struct qslave_recov_thread_data {
+ struct obd_device *obd;
+ struct lustre_quota_ctxt *qctxt;
+ struct completion comp;
+};
+
+/* FIXME only recovery block quota by now */
+static int qslave_recovery_main(void *arg)
+{
+ struct qslave_recov_thread_data *data = arg;
+ struct obd_device *obd = data->obd;
+ struct lustre_quota_ctxt *qctxt = data->qctxt;
+ unsigned long flags;
+ unsigned int type;
+ int rc = 0;
+ ENTRY;
+
+ lock_kernel();
+ ptlrpc_daemonize();
+
+ SIGNAL_MASK_LOCK(current, flags);
+ sigfillset(¤t->blocked);
+ RECALC_SIGPENDING;
+ SIGNAL_MASK_UNLOCK(current, flags);
+ THREAD_NAME(cfs_curproc_comm(), CFS_CURPROC_COMM_MAX - 1, "%s", "qslave_recovd");
+ unlock_kernel();
+
+ complete(&data->comp);
+
+ if (qctxt->lqc_recovery)
+ RETURN(0);
+ qctxt->lqc_recovery = 1;
+
+ for (type = USRQUOTA; type < MAXQUOTAS; type++) {
+ struct qunit_data qdata;
+ struct quota_info *dqopt = sb_dqopt(qctxt->lqc_sb);
+ struct lustre_quota_info *dummy;
+ struct list_head id_list;
+ struct dquot_id *dqid, *tmp;
+ int ret;
+
+ OBD_ALLOC_PTR(dummy);
+ if (!dummy) {
+ CERROR("Not enough memory\n");
+ rc = -ENOMEM;
+ break;
+ }
+
+ down(&dqopt->dqonoff_sem);
+ if (!sb_has_quota_enabled(qctxt->lqc_sb, type)) {
+ up(&dqopt->dqonoff_sem);
+ OBD_FREE_PTR(dummy);
+ break;
+ }
+ dummy->qi_files[type] = dqopt->files[type];
+ LASSERT(dummy->qi_files[type] != NULL);
+ INIT_LIST_HEAD(&id_list);
+
+ rc = fsfilt_quotainfo(obd, dummy, type, QFILE_GET_QIDS, &id_list);
+ up(&dqopt->dqonoff_sem);
+
+ OBD_FREE_PTR(dummy);
+ if (rc)
+ CERROR("Get ids from quota file failed. (rc:%d)\n", rc);
+
+ list_for_each_entry_safe(dqid, tmp, &id_list, di_link) {
+ list_del_init(&dqid->di_link);
+ /* skip slave recovery on itself */
+ if (is_master(obd, qctxt, dqid->di_id, type))
+ goto free;
+ if (rc && rc != -EBUSY)
+ goto free;
+
+ qdata.qd_id = dqid->di_id;
+ qdata.qd_type = type;
+ qdata.qd_isblk = 1;
+ qdata.qd_count = 0;
+
+ ret = check_cur_qunit(obd, qctxt, &qdata);
+ if (ret > 0) {
+ int opc;
+ opc = ret == 1 ? QUOTA_DQACQ : QUOTA_DQREL;
+ rc = schedule_dqacq(obd, qctxt, &qdata, opc, 0);
+ } else
+ rc = 0;
+
+ if (rc)
+ CDEBUG(rc == -EBUSY ? D_QUOTA : D_ERROR,
+ "qslave recovery failed! (id:%d type:%d "
+ " rc:%d)\n", dqid->di_id, type, rc);
+free:
+ kfree(dqid);
+ }
+ }
+
+ qctxt->lqc_recovery = 0;
+ RETURN(rc);
+}
+
+void
+qslave_start_recovery(struct obd_device *obd, struct lustre_quota_ctxt *qctxt)
+{
+ struct qslave_recov_thread_data data;
+ int rc;
+ ENTRY;
+
+ if (!sb_any_quota_enabled(qctxt->lqc_sb))
+ goto exit;
+
+ data.obd = obd;
+ data.qctxt = qctxt;
+ init_completion(&data.comp);
+
+ rc = kernel_thread(qslave_recovery_main, &data, CLONE_VM|CLONE_FILES);
+ if (rc < 0) {
+ CERROR("Cannot start quota recovery thread: rc %d\n", rc);
+ goto exit;
+ }
+ wait_for_completion(&data.comp);
+exit:
+ EXIT;
+}
+
--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * lustre/quota/quota_ctl.c
+ *
+ * Copyright (c) 2005 Cluster File Systems, Inc.
+ *
+ * This file is part of Lustre, http://www.lustre.org.
+ *
+ * No redistribution or use is permitted outside of Cluster File Systems, Inc.
+ *
+ */
+#ifndef EXPORT_SYMTAB
+# define EXPORT_SYMTAB
+#endif
+#define DEBUG_SUBSYSTEM S_MDS
+
+#ifdef __KERNEL__
+# include <linux/version.h>
+# include <linux/module.h>
+# include <linux/init.h>
+# include <linux/fs.h>
+# include <linux/jbd.h>
+# include <linux/ext3_fs.h>
+# include <linux/quota.h>
+# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+# include <linux/smp_lock.h>
+# include <linux/buffer_head.h>
+# include <linux/workqueue.h>
+# include <linux/mount.h>
+# else
+# include <linux/locks.h>
+# endif
+#else /* __KERNEL__ */
+# include <liblustre.h>
+#endif
+
+#include <linux/obd_class.h>
+#include <linux/lustre_mds.h>
+#include <linux/lustre_dlm.h>
+#include <linux/lustre_cfg.h>
+#include <linux/obd_ost.h>
+#include <linux/lustre_fsfilt.h>
+#include <linux/lustre_quota.h>
+#include "quota_internal.h"
+
+#ifdef __KERNEL__
+int mds_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl)
+{
+ struct obd_device *obd = exp->exp_obd;
+ int rc = 0;
+ ENTRY;
+
+ switch (oqctl->qc_cmd) {
+ case Q_QUOTAON:
+ rc = mds_quota_on(obd, oqctl);
+ break;
+ case Q_QUOTAOFF:
+ mds_quota_off(obd, oqctl);
+ break;
+ case Q_SETINFO:
+ rc = mds_set_dqinfo(obd, oqctl);
+ break;
+ case Q_GETINFO:
+ rc = mds_get_dqinfo(obd, oqctl);
+ break;
+ case Q_SETQUOTA:
+ rc = mds_set_dqblk(obd, oqctl);
+ break;
+ case Q_GETQUOTA:
+ rc = mds_get_dqblk(obd, oqctl);
+ break;
+ case Q_GETOINFO:
+ case Q_GETOQUOTA:
+ rc = mds_get_obd_quota(obd, oqctl);
+ break;
+ default:
+ CERROR("%s: unsupported mds_quotactl command: %d\n",
+ obd->obd_name, oqctl->qc_cmd);
+ RETURN(-EFAULT);
+ }
+
+ if (rc)
+ CDEBUG(D_INFO, "mds_quotactl admin quota command %d, id %u, "
+ "type %d, failed: rc = %d\n",
+ oqctl->qc_cmd, oqctl->qc_id, oqctl->qc_type, rc);
+
+ RETURN(rc);
+}
+
+int filter_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl)
+{
+ struct obd_device *obd = exp->exp_obd;
+ struct lvfs_run_ctxt saved;
+ int rc = 0;
+ ENTRY;
+
+ switch (oqctl->qc_cmd) {
+ case Q_QUOTAON:
+ case Q_QUOTAOFF:
+ case Q_GETOINFO:
+ case Q_GETOQUOTA:
+ case Q_GETQUOTA:
+ /* In recovery scenario, this pending dqacq/dqrel might have
+ * been processed by master successfully before it's dquot
+ * on master enter recovery mode. We must wait for this
+ * dqacq/dqrel done then return the correct limits to master */
+ if (oqctl->qc_stat == QUOTA_RECOVERING)
+ qctxt_wait_pending_dqacq(&obd->u.obt.obt_qctxt,
+ oqctl->qc_id, oqctl->qc_type,
+ 1);
+
+ push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+ rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
+ pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+ break;
+ case Q_INITQUOTA:
+ {
+ unsigned int uid = 0, gid = 0;
+
+ /* Initialize quota limit to MIN_QLIMIT */
+ LASSERT(oqctl->qc_dqblk.dqb_valid == QIF_BLIMITS);
+ LASSERT(oqctl->qc_dqblk.dqb_bhardlimit == MIN_QLIMIT);
+ LASSERT(oqctl->qc_dqblk.dqb_bsoftlimit == 0);
+
+ /* There might be a pending dqacq/dqrel (which is going to
+ * clear stale limits on slave). we should wait for it's
+ * completion then initialize limits */
+ qctxt_wait_pending_dqacq(&obd->u.obt.obt_qctxt,
+ oqctl->qc_id, oqctl->qc_type, 1);
+
+ push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+ rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
+
+ /* Update on-disk quota, in case of lose the changed limits
+ * (MIN_QLIMIT) on crash, which cannot be recovered.*/
+ if (!rc) {
+ oqctl->qc_cmd = Q_SYNC;
+ fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
+ oqctl->qc_cmd = Q_INITQUOTA;
+ }
+ pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+
+ if (rc)
+ RETURN(rc);
+
+ /* Trigger qunit pre-acquire */
+ if (oqctl->qc_type == USRQUOTA)
+ uid = oqctl->qc_id;
+ else
+ gid = oqctl->qc_id;
+
+ rc = qctxt_adjust_qunit(obd, &obd->u.obt.obt_qctxt,
+ uid, gid, 1, 0);
+ break;
+ }
+ default:
+ CERROR("%s: unsupported filter_quotactl command: %d\n",
+ obd->obd_name, oqctl->qc_cmd);
+ RETURN(-EFAULT);
+ }
+
+ RETURN(rc);
+}
+#endif /* __KERNEL__ */
+
+int client_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl)
+{
+ struct ptlrpc_request *req;
+ struct obd_quotactl *oqc;
+ int size = sizeof(*oqctl), opc;
+ int rc;
+ ENTRY;
+
+ if (!strcmp(exp->exp_obd->obd_type->typ_name, LUSTRE_MDC_NAME))
+ opc = MDS_QUOTACTL;
+ else if (!strcmp(exp->exp_obd->obd_type->typ_name, LUSTRE_OSC_NAME))
+ opc = OST_QUOTACTL;
+ else
+ RETURN(-EINVAL);
+
+ req = ptlrpc_prep_req(class_exp2cliimp(exp), opc, 1, &size, NULL);
+ if (!req)
+ GOTO(out, rc = -ENOMEM);
+
+ oqc = lustre_msg_buf(req->rq_reqmsg, 0, sizeof (*oqctl));
+ *oqc = *oqctl;
+
+ req->rq_replen = lustre_msg_size(1, &size);
+
+ rc = ptlrpc_queue_wait(req);
+ if (!rc) {
+ oqc = lustre_swab_repbuf(req, 0, sizeof (*oqc),
+ lustre_swab_obd_quotactl);
+ if (oqc == NULL) {
+ CERROR ("Can't unpack obd_quotactl\n");
+ GOTO(out, rc = -EPROTO);
+ }
+
+ *oqctl = *oqc;
+ }
+out:
+ ptlrpc_req_finished(req);
+ RETURN (rc);
+}
+
+int lov_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl)
+{
+ struct obd_device *obd = class_exp2obd(exp);
+ struct lov_obd *lov = &obd->u.lov;
+ __u64 curspace = 0;
+ __u32 bhardlimit = 0;
+ int i, rc = 0;
+ ENTRY;
+
+ if (oqctl->qc_cmd != Q_QUOTAON && oqctl->qc_cmd != Q_QUOTAOFF &&
+ oqctl->qc_cmd != Q_GETOQUOTA && oqctl->qc_cmd != Q_INITQUOTA) {
+ CERROR("bad quota opc %x for lov obd", oqctl->qc_cmd);
+ RETURN(-EFAULT);
+ }
+
+ for (i = 0; i < lov->desc.ld_tgt_count; i++) {
+ int err;
+
+ if (!lov->tgts[i].active) {
+ if (oqctl->qc_cmd == Q_GETOQUOTA) {
+ CERROR("ost %d is inactive\n", i);
+ rc = -EIO;
+ break;
+ } else {
+ CDEBUG(D_HA, "ost %d is inactive\n", i);
+ continue;
+ }
+ }
+
+ err = obd_quotactl(lov->tgts[i].ltd_exp, oqctl);
+ if (err) {
+ if (lov->tgts[i].active && !rc)
+ rc = err;
+ continue;
+ }
+
+ if (oqctl->qc_cmd == Q_GETOQUOTA) {
+ curspace += oqctl->qc_dqblk.dqb_curspace;
+ bhardlimit += oqctl->qc_dqblk.dqb_bhardlimit;
+ }
+ }
+
+ if (oqctl->qc_cmd == Q_GETOQUOTA) {
+ oqctl->qc_dqblk.dqb_curspace = curspace;
+ oqctl->qc_dqblk.dqb_bhardlimit = bhardlimit;
+ }
+ RETURN(rc);
+}
+
--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * lustre/quota/quota_interface.c
+ *
+ * Copyright (c) 2001-2005 Cluster File Systems, Inc.
+ *
+ * This file is part of Lustre, http://www.lustre.org.
+ *
+ * No redistribution or use is permitted outside of Cluster File Systems, Inc.
+ *
+ */
+#ifndef EXPORT_SYMTAB
+# define EXPORT_SYMTAB
+#endif
+#define DEBUG_SUBSYSTEM S_MDS
+
+#ifdef __KERNEL__
+# include <linux/version.h>
+# include <linux/module.h>
+# include <linux/init.h>
+# include <linux/fs.h>
+# include <linux/jbd.h>
+# include <linux/ext3_fs.h>
+# include <linux/parser.h>
+# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+# include <linux/smp_lock.h>
+# include <linux/buffer_head.h>
+# include <linux/workqueue.h>
+# include <linux/mount.h>
+# else
+# include <linux/locks.h>
+# endif
+#else /* __KERNEL__ */
+# include <liblustre.h>
+#endif
+
+#include <linux/obd_class.h>
+#include <linux/lustre_mds.h>
+#include <linux/lustre_dlm.h>
+#include <linux/lustre_cfg.h>
+#include <linux/obd_ost.h>
+#include <linux/lustre_fsfilt.h>
+#include <linux/lustre_quota.h>
+#include "quota_internal.h"
+
+
+#ifdef __KERNEL__
+extern unsigned long default_bunit_sz;
+extern unsigned long default_btune_ratio;
+extern unsigned long default_iunit_sz;
+extern unsigned long default_itune_ratio;
+
+enum {
+ Opt_quotaon, Opt_iunit_sz, Opt_bunit_sz,
+ Opt_itune_ratio, Opt_btune_ratio, Opt_err,
+};
+
+static match_table_t tokens = {
+ {Opt_quotaon, "quotaon=%10s"},
+ {Opt_iunit_sz, "iunit=%u"},
+ {Opt_bunit_sz, "bunit=%u"},
+ {Opt_itune_ratio, "itune=%u"},
+ {Opt_btune_ratio, "btune=%u"},
+ {Opt_err, NULL}
+};
+
+static int
+quota_parse_config_args(char *options, int *quotaon, int *type,
+ struct lustre_quota_ctxt *qctxt)
+{
+ char *opt;
+ substring_t args[MAX_OPT_ARGS];
+ int option;
+ int rc = 0;
+ unsigned long iunit = 0, bunit = 0, itune = 0, btune = 0;
+ ENTRY;
+
+ while ((opt = strsep (&options, ",")) != NULL) {
+ int token;
+ if (!*opt)
+ continue;
+
+ token = match_token(opt, tokens, args);
+ switch(token) {
+ case Opt_quotaon: {
+ char *quota_type = match_strdup(&args[0]);
+ if (!quota_type)
+ GOTO(out, rc = -EINVAL);
+
+ *quotaon = 1;
+ if (strchr(quota_type, 'u') && strchr(quota_type, 'g'))
+ *type = UGQUOTA;
+ else if (strchr(quota_type, 'u'))
+ *type = USRQUOTA;
+ else if (strchr(quota_type, 'g'))
+ *type = GRPQUOTA;
+ else {
+ *quotaon = 0;
+ rc = -EINVAL;
+ }
+ break;
+ }
+ case Opt_iunit_sz:
+ if (match_int(&args[0], &option))
+ rc = -EINVAL;
+ iunit = option;
+ break;
+ case Opt_bunit_sz:
+ if (match_int(&args[0], &option))
+ rc = -EINVAL;
+ bunit = option;
+ break;
+ case Opt_itune_ratio:
+ if (match_int(&args[0], &option) ||
+ option <= 0 || option >= 100)
+ rc = -EINVAL;
+ itune = option;
+ break;
+ case Opt_btune_ratio:
+ if (match_int(&args[0], &option) ||
+ option <= 0 || option >= 100)
+ rc = -EINVAL;
+ btune = option;
+ break;
+ default:
+ rc = -EINVAL;
+ }
+
+ if (rc)
+ GOTO(out, rc);
+ }
+
+ /* adjust the tunables of qunits based on quota config args */
+ if (iunit)
+ qctxt->lqc_iunit_sz = iunit;
+ if (itune)
+ qctxt->lqc_itune_sz = qctxt->lqc_iunit_sz *
+ itune / 100;
+ else
+ qctxt->lqc_itune_sz = qctxt->lqc_iunit_sz *
+ default_itune_ratio / 100;
+ if (bunit)
+ qctxt->lqc_bunit_sz = bunit << 20;
+ if (btune)
+ qctxt->lqc_btune_sz = ((qctxt->lqc_bunit_sz >> 20) *
+ btune / 100) << 20;
+ else
+ qctxt->lqc_btune_sz = ((qctxt->lqc_bunit_sz >> 20) *
+ default_btune_ratio / 100) << 20;
+
+ CDEBUG(D_INFO, "iunit=%lu bunit=%lu itune=%lu btune=%lu\n",
+ qctxt->lqc_iunit_sz, qctxt->lqc_bunit_sz,
+ qctxt->lqc_itune_sz, qctxt->lqc_btune_sz);
+ EXIT;
+
+ out:
+ if (rc)
+ CERROR("quota config args parse error!(rc = %d) usage: "
+ "--quota quotaon=u|g|ug,iunit=100,bunit=100,itune=50,btune=50\n",
+ rc);
+
+ return rc;
+}
+
+static int auto_quota_on(struct obd_device *obd, int type,
+ struct super_block *sb, int is_master)
+{
+ struct obd_quotactl *oqctl;
+ struct lvfs_run_ctxt saved;
+ int rc;
+ ENTRY;
+
+ LASSERT(type == USRQUOTA || type == GRPQUOTA || type == UGQUOTA);
+
+ OBD_ALLOC_PTR(oqctl);
+ if (!oqctl)
+ RETURN(-ENOMEM);
+
+ oqctl->qc_type = type;
+ oqctl->qc_cmd = Q_QUOTAON;
+ oqctl->qc_id = QFMT_LDISKFS;
+
+ push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+
+ if (!is_master)
+ goto local_quota;
+
+ /* turn on cluster wide quota */
+ rc = mds_admin_quota_on(obd, oqctl);
+ if (rc) {
+ CERROR("auto enable admin quota error! err = %d\n", rc);
+ GOTO(out_pop, rc);
+ }
+local_quota:
+ /* turn on local quota */
+ rc = fsfilt_quotactl(obd, sb, oqctl);
+ CDEBUG(rc ? D_ERROR : D_INFO, "auto-enable quota. rc=%d\n", rc);
+ if (rc && is_master)
+ mds_quota_off(obd, oqctl);
+out_pop:
+ pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+
+ OBD_FREE_PTR(oqctl);
+ RETURN(rc);
+}
+
+static int mds_auto_quota_on(struct obd_device *obd, int type)
+{
+ int rc;
+ ENTRY;
+ rc = auto_quota_on(obd, type, obd->u.obt.obt_sb, 1);
+ RETURN(rc);
+}
+
+static int filter_auto_quota_on(struct obd_device *obd, int type)
+{
+ int rc = 0;
+ ENTRY;
+ rc = auto_quota_on(obd, type, obd->u.obt.obt_sb, 0);
+ RETURN(rc);
+}
+
+static int filter_quota_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
+{
+ int rc = 0;
+ struct obd_device_target *obt = &obd->u.obt;
+ ENTRY;
+
+ atomic_set(&obt->obt_quotachecking, 1);
+ rc = qctxt_init(&obt->obt_qctxt, obt->obt_sb, NULL);
+ if (rc) {
+ CERROR("initialize quota context failed! (rc:%d)\n", rc);
+ RETURN(rc);
+ }
+
+ /* Based on quota config args, set qunit sizes and enable quota */
+ if (LUSTRE_CFG_BUFLEN(lcfg, 5) > 0 && lustre_cfg_buf(lcfg, 5)) {
+ char *args = lustre_cfg_string(lcfg, 5);
+ int quotaon = 0, type;
+ int err = 0;
+
+ err = quota_parse_config_args(args, "aon, &type,
+ &obd->u.obt.obt_qctxt);
+ if (!err && quotaon)
+ filter_auto_quota_on(obd, type);
+ }
+
+ RETURN(rc);
+}
+
+static int filter_quota_cleanup(struct obd_device *obd)
+{
+ qctxt_cleanup(&obd->u.obt.obt_qctxt, 0);
+ return 0;
+}
+
+static int filter_quota_setinfo(struct obd_export *exp, struct obd_device *obd)
+{
+ /* setup the quota context import */
+ obd->u.obt.obt_qctxt.lqc_import = exp->exp_imp_reverse;
+ /* start quota slave recovery thread. (release high limits) */
+ qslave_start_recovery(obd, &obd->u.obt.obt_qctxt);
+ return 0;
+}
+static int filter_quota_enforce(struct obd_device *obd, unsigned int ignore)
+{
+ ENTRY;
+
+ if (!sb_any_quota_enabled(obd->u.obt.obt_sb))
+ RETURN(0);
+
+ if (ignore)
+ cap_raise(current->cap_effective, CAP_SYS_RESOURCE);
+ else
+ cap_lower(current->cap_effective, CAP_SYS_RESOURCE);
+
+ RETURN(0);
+}
+
+static int filter_quota_getflag(struct obd_device *obd, struct obdo *oa)
+{
+ struct obd_device_target *obt = &obd->u.obt;
+ int err, cnt, rc = 0;
+ struct obd_quotactl *oqctl;
+ ENTRY;
+
+ if (!sb_any_quota_enabled(obt->obt_sb))
+ RETURN(0);
+
+ oa->o_flags &= ~(OBD_FL_NO_USRQUOTA | OBD_FL_NO_GRPQUOTA);
+
+ OBD_ALLOC_PTR(oqctl);
+ if (!oqctl) {
+ CERROR("Not enough memory!");
+ RETURN(-ENOMEM);
+ }
+
+ for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+ memset(oqctl, 0, sizeof(*oqctl));
+
+ oqctl->qc_cmd = Q_GETQUOTA;
+ oqctl->qc_type = cnt;
+ oqctl->qc_id = (cnt == USRQUOTA) ? oa->o_uid : oa->o_gid;
+ err = fsfilt_quotactl(obd, obt->obt_sb, oqctl);
+ if (err) {
+ if (!rc)
+ rc = err;
+ continue;
+ }
+
+ /* set over quota flags for a uid/gid */
+ oa->o_valid |= (cnt == USRQUOTA) ?
+ OBD_MD_FLUSRQUOTA : OBD_MD_FLGRPQUOTA;
+ if (oqctl->qc_dqblk.dqb_bhardlimit &&
+ (toqb(oqctl->qc_dqblk.dqb_curspace) >
+ oqctl->qc_dqblk.dqb_bhardlimit))
+ oa->o_flags |= (cnt == USRQUOTA) ?
+ OBD_FL_NO_USRQUOTA : OBD_FL_NO_GRPQUOTA;
+ }
+ OBD_FREE_PTR(oqctl);
+ RETURN(rc);
+}
+
+static int filter_quota_acquire(struct obd_device *obd, unsigned int uid,
+ unsigned int gid)
+{
+ struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
+ int rc;
+ ENTRY;
+
+ rc = qctxt_adjust_qunit(obd, qctxt, uid, gid, 1, 1);
+ RETURN(rc == -EAGAIN);
+}
+
+static int mds_quota_init(void)
+{
+ return lustre_dquot_init();
+}
+
+static int mds_quota_exit(void)
+{
+ lustre_dquot_exit();
+ return 0;
+}
+
+static int mds_quota_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
+{
+ struct obd_device_target *obt = &obd->u.obt;
+ struct mds_obd *mds = &obd->u.mds;
+ int rc;
+ ENTRY;
+
+ atomic_set(&obt->obt_quotachecking, 1);
+ /* initialize quota master and quota context */
+ sema_init(&mds->mds_qonoff_sem, 1);
+ rc = qctxt_init(&obt->obt_qctxt, obt->obt_sb, dqacq_handler);
+ if (rc) {
+ CERROR("initialize quota context failed! (rc:%d)\n", rc);
+ RETURN(rc);
+ }
+
+ /* Based on quota config args, set qunit sizes and enable quota */
+ if (LUSTRE_CFG_BUFLEN(lcfg, 5) > 0 && lustre_cfg_buf(lcfg, 5)) {
+ char *args = lustre_cfg_string(lcfg, 5);
+ int quotaon = 0, type;
+ int err;
+
+ err = quota_parse_config_args(args, "aon, &type,
+ &obt->obt_qctxt);
+ if (!err && quotaon)
+ mds_auto_quota_on(obd, type);
+ }
+ RETURN(rc);
+}
+
+static int mds_quota_cleanup(struct obd_device *obd)
+{
+ qctxt_cleanup(&obd->u.obt.obt_qctxt, 0);
+ RETURN(0);
+}
+
+static int mds_quota_fs_cleanup(struct obd_device *obd)
+{
+ struct mds_obd *mds = &obd->u.mds;
+ int i;
+ ENTRY;
+
+ /* close admin quota files */
+ down(&mds->mds_qonoff_sem);
+ for (i = 0; i < MAXQUOTAS; i++) {
+ if (mds->mds_quota_info.qi_files[i]) {
+ filp_close(mds->mds_quota_info.qi_files[i], 0);
+ mds->mds_quota_info.qi_files[i] = NULL;
+ }
+ }
+ up(&mds->mds_qonoff_sem);
+ RETURN(0);
+}
+#endif /* __KERNEL__ */
+
+struct osc_quota_info {
+ struct list_head oqi_hash; /* hash list */
+ struct client_obd *oqi_cli; /* osc obd */
+ unsigned int oqi_id; /* uid/gid of a file */
+ short oqi_type; /* quota type */
+};
+
+spinlock_t qinfo_list_lock = SPIN_LOCK_UNLOCKED;
+
+static struct list_head qinfo_hash[NR_DQHASH];
+/* SLAB cache for client quota context */
+kmem_cache_t *qinfo_cachep = NULL;
+
+static inline int const hashfn(struct client_obd *cli,
+ unsigned long id,
+ int type)
+{
+ unsigned long tmp = ((unsigned long)cli>>6) ^ id;
+ tmp = (tmp * (MAXQUOTAS - type)) % NR_DQHASH;
+ return tmp;
+}
+
+/* caller must hold qinfo_list_lock */
+static inline void insert_qinfo_hash(struct osc_quota_info *oqi)
+{
+ struct list_head *head = qinfo_hash +
+ hashfn(oqi->oqi_cli, oqi->oqi_id, oqi->oqi_type);
+
+ LASSERT_SPIN_LOCKED(&qinfo_list_lock);
+ list_add(&oqi->oqi_hash, head);
+}
+
+/* caller must hold qinfo_list_lock */
+static inline void remove_qinfo_hash(struct osc_quota_info *oqi)
+{
+ LASSERT_SPIN_LOCKED(&qinfo_list_lock);
+ list_del_init(&oqi->oqi_hash);
+}
+
+/* caller must hold qinfo_list_lock */
+static inline struct osc_quota_info *find_qinfo(struct client_obd *cli,
+ unsigned int id, int type)
+{
+ unsigned int hashent = hashfn(cli, id, type);
+ struct osc_quota_info *oqi;
+
+ LASSERT_SPIN_LOCKED(&qinfo_list_lock);
+ list_for_each_entry(oqi, &qinfo_hash[hashent], oqi_hash) {
+ if (oqi->oqi_cli == cli &&
+ oqi->oqi_id == id && oqi->oqi_type == type)
+ return oqi;
+ }
+ return NULL;
+}
+
+static struct osc_quota_info *alloc_qinfo(struct client_obd *cli,
+ unsigned int id, int type)
+{
+ struct osc_quota_info *oqi;
+ ENTRY;
+
+ OBD_SLAB_ALLOC(oqi, qinfo_cachep, SLAB_KERNEL, sizeof(*oqi));
+ if(!oqi)
+ RETURN(NULL);
+
+ INIT_LIST_HEAD(&oqi->oqi_hash);
+ oqi->oqi_cli = cli;
+ oqi->oqi_id = id;
+ oqi->oqi_type = type;
+
+ RETURN(oqi);
+}
+
+static void free_qinfo(struct osc_quota_info *oqi)
+{
+ OBD_SLAB_FREE(oqi, qinfo_cachep, sizeof(*oqi));
+}
+
+int osc_quota_chkdq(struct client_obd *cli,
+ unsigned int uid, unsigned int gid)
+{
+ unsigned int id;
+ int cnt, rc = QUOTA_OK;
+ ENTRY;
+
+ spin_lock(&qinfo_list_lock);
+ for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+ struct osc_quota_info *oqi = NULL;
+
+ id = (cnt == USRQUOTA) ? uid : gid;
+ oqi = find_qinfo(cli, id, cnt);
+ if (oqi) {
+ rc = NO_QUOTA;
+ break;
+ }
+ }
+ spin_unlock(&qinfo_list_lock);
+
+ RETURN(rc);
+}
+
+int osc_quota_setdq(struct client_obd *cli,
+ unsigned int uid, unsigned int gid,
+ obd_flag valid, obd_flag flags)
+{
+ unsigned int id;
+ obd_flag noquota;
+ int cnt, rc = 0;
+ ENTRY;
+
+
+ for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+ struct osc_quota_info *oqi, *old;
+
+ if (!(valid & ((cnt == USRQUOTA) ?
+ OBD_MD_FLUSRQUOTA : OBD_MD_FLGRPQUOTA)))
+ continue;
+
+ id = (cnt == USRQUOTA) ? uid : gid;
+ noquota = (cnt == USRQUOTA) ?
+ (flags & OBD_FL_NO_USRQUOTA) : (flags & OBD_FL_NO_GRPQUOTA);
+
+ oqi = alloc_qinfo(cli, id, cnt);
+ if (oqi) {
+ spin_lock(&qinfo_list_lock);
+
+ old = find_qinfo(cli, id, cnt);
+ if (old && !noquota)
+ remove_qinfo_hash(old);
+ else if (!old && noquota)
+ insert_qinfo_hash(oqi);
+
+ spin_unlock(&qinfo_list_lock);
+
+ if (old || !noquota)
+ free_qinfo(oqi);
+ if (old && !noquota)
+ free_qinfo(old);
+ } else {
+ CERROR("not enough mem!\n");
+ rc = -ENOMEM;
+ break;
+ }
+ }
+
+ RETURN(rc);
+}
+
+int osc_quota_cleanup(struct obd_device *obd)
+{
+ struct client_obd *cli = &obd->u.cli;
+ struct osc_quota_info *oqi, *n;
+ int i;
+ ENTRY;
+
+ spin_lock(&qinfo_list_lock);
+ for (i = 0; i < NR_DQHASH; i++) {
+ list_for_each_entry_safe(oqi, n, &qinfo_hash[i], oqi_hash) {
+ if (oqi->oqi_cli != cli)
+ continue;
+ remove_qinfo_hash(oqi);
+ free_qinfo(oqi);
+ }
+ }
+ spin_unlock(&qinfo_list_lock);
+
+ RETURN(0);
+}
+
+int osc_quota_init(void)
+{
+ int i;
+ ENTRY;
+
+ LASSERT(qinfo_cachep == NULL);
+ qinfo_cachep = kmem_cache_create("osc_quota_info",
+ sizeof(struct osc_quota_info),
+ 0, 0, NULL, NULL);
+ if (!qinfo_cachep)
+ RETURN(-ENOMEM);
+
+ for (i = 0; i < NR_DQHASH; i++)
+ INIT_LIST_HEAD(qinfo_hash + i);
+
+ RETURN(0);
+}
+
+int osc_quota_exit(void)
+{
+ struct osc_quota_info *oqi, *n;
+ int i, rc;
+ ENTRY;
+
+ spin_lock(&qinfo_list_lock);
+ for (i = 0; i < NR_DQHASH; i++) {
+ list_for_each_entry_safe(oqi, n, &qinfo_hash[i], oqi_hash) {
+ remove_qinfo_hash(oqi);
+ free_qinfo(oqi);
+ }
+ }
+ spin_unlock(&qinfo_list_lock);
+
+ rc = kmem_cache_destroy(qinfo_cachep);
+ LASSERT(rc == 0);
+ RETURN(0);
+}
+
+#ifdef __KERNEL__
+quota_interface_t mds_quota_interface = {
+ .quota_init = mds_quota_init,
+ .quota_exit = mds_quota_exit,
+ .quota_setup = mds_quota_setup,
+ .quota_cleanup = mds_quota_cleanup,
+ .quota_check = target_quota_check,
+ .quota_ctl = mds_quota_ctl,
+ .quota_fs_cleanup =mds_quota_fs_cleanup,
+ .quota_recovery = mds_quota_recovery,
+ .quota_adjust = mds_quota_adjust,
+};
+
+quota_interface_t filter_quota_interface = {
+ .quota_setup = filter_quota_setup,
+ .quota_cleanup = filter_quota_cleanup,
+ .quota_check = target_quota_check,
+ .quota_ctl = filter_quota_ctl,
+ .quota_setinfo = filter_quota_setinfo,
+ .quota_enforce = filter_quota_enforce,
+ .quota_getflag = filter_quota_getflag,
+ .quota_acquire = filter_quota_acquire,
+ .quota_adjust = filter_quota_adjust,
+};
+#endif /* __KERNEL__ */
+
+quota_interface_t mdc_quota_interface = {
+ .quota_ctl = client_quota_ctl,
+ .quota_check = client_quota_check,
+ .quota_poll_check = client_quota_poll_check,
+};
+
+quota_interface_t osc_quota_interface = {
+ .quota_ctl = client_quota_ctl,
+ .quota_check = client_quota_check,
+ .quota_poll_check = client_quota_poll_check,
+ .quota_init = osc_quota_init,
+ .quota_exit = osc_quota_exit,
+ .quota_chkdq = osc_quota_chkdq,
+ .quota_setdq = osc_quota_setdq,
+ .quota_cleanup = osc_quota_cleanup,
+};
+
+quota_interface_t lov_quota_interface = {
+ .quota_check = lov_quota_check,
+ .quota_ctl = lov_quota_ctl,
+};
+
+#ifdef __KERNEL__
+static int __init init_lustre_quota(void)
+{
+ int rc = qunit_cache_init();
+ if (rc)
+ return rc;
+ PORTAL_SYMBOL_REGISTER(filter_quota_interface);
+ PORTAL_SYMBOL_REGISTER(mds_quota_interface);
+ PORTAL_SYMBOL_REGISTER(mdc_quota_interface);
+ PORTAL_SYMBOL_REGISTER(osc_quota_interface);
+ PORTAL_SYMBOL_REGISTER(lov_quota_interface);
+ return 0;
+}
+
+static void /*__exit*/ exit_lustre_quota(void)
+{
+ PORTAL_SYMBOL_UNREGISTER(filter_quota_interface);
+ PORTAL_SYMBOL_UNREGISTER(mds_quota_interface);
+ PORTAL_SYMBOL_UNREGISTER(mdc_quota_interface);
+ PORTAL_SYMBOL_UNREGISTER(osc_quota_interface);
+ PORTAL_SYMBOL_UNREGISTER(lov_quota_interface);
+
+ qunit_cache_cleanup();
+}
+
+MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
+MODULE_DESCRIPTION("Lustre Quota");
+MODULE_LICENSE("GPL");
+
+cfs_module(lquota, "1.0.0", init_lustre_quota, exit_lustre_quota);
+
+EXPORT_SYMBOL(mds_quota_interface);
+EXPORT_SYMBOL(filter_quota_interface);
+EXPORT_SYMBOL(mdc_quota_interface);
+EXPORT_SYMBOL(osc_quota_interface);
+EXPORT_SYMBOL(lov_quota_interface);
+#endif /* __KERNEL */
--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * lustre/quota/quota_internal.h
+ *
+ * Copyright (c) 2001-2005 Cluster File Systems, Inc.
+ *
+ * This file is part of Lustre, http://www.lustre.org.
+ *
+ * No redistribution or use is permitted outside of Cluster File Systems, Inc.
+ *
+ */
+
+#ifndef __QUOTA_INTERNAL_H
+#define __QUOTA_INTERNAL_H
+
+#include <linux/lustre_quota.h>
+
+/* QUSG covnert bytes to blocks when counting block quota */
+#define QUSG(count, isblk) (isblk ? toqb(count) : count)
+
+/* This flag is set in qc_stat to distinguish if the current getquota
+ * operation is for quota recovery */
+#define QUOTA_RECOVERING 0x01
+
+#ifdef __KERNEL__
+
+#define DQUOT_DEBUG(dquot, fmt, arg...) \
+ CDEBUG(D_QUOTA, "refcnt(%u) id(%u) type(%u) off(%llu) flags(%lu) " \
+ "bhardlimit(%u) curspace("LPX64") ihardlimit(%u) " \
+ "curinodes(%u): " fmt, dquot->dq_refcnt, \
+ dquot->dq_id, dquot->dq_type, dquot->dq_off, dquot->dq_flags, \
+ dquot->dq_dqb.dqb_bhardlimit, dquot->dq_dqb.dqb_curspace, \
+ dquot->dq_dqb.dqb_ihardlimit, dquot->dq_dqb.dqb_curinodes, \
+ ## arg); \
+
+#define QINFO_DEBUG(qinfo, fmt, arg...) \
+ CDEBUG(D_QUOTA, "files (%p/%p) flags(%lu/%lu) blocks(%u/%u) " \
+ "free_blk(/%u/%u) free_entry(%u/%u): " fmt, \
+ qinfo->qi_files[0], qinfo->qi_files[1], \
+ qinfo->qi_info[0].dqi_flags, qinfo->qi_info[1].dqi_flags, \
+ qinfo->qi_info[0].dqi_blocks, qinfo->qi_info[1].dqi_blocks, \
+ qinfo->qi_info[0].dqi_free_blk, qinfo->qi_info[1].dqi_free_blk,\
+ qinfo->qi_info[0].dqi_free_entry, \
+ qinfo->qi_info[1].dqi_free_entry, ## arg);
+
+/* quota_context.c */
+void qunit_cache_cleanup(void);
+int qunit_cache_init(void);
+int qctxt_adjust_qunit(struct obd_device *obd, struct lustre_quota_ctxt *qctxt,
+ uid_t uid, gid_t gid, __u32 isblk, int wait);
+int qctxt_wait_pending_dqacq(struct lustre_quota_ctxt *qctxt, unsigned int id,
+ unsigned short type, int isblk);
+int qctxt_init(struct lustre_quota_ctxt *qctxt, struct super_block *sb,
+ dqacq_handler_t handler);
+void qctxt_cleanup(struct lustre_quota_ctxt *qctxt, int force);
+void qslave_start_recovery(struct obd_device *obd,
+ struct lustre_quota_ctxt *qctxt);
+/* quota_master.c */
+int lustre_dquot_init(void);
+void lustre_dquot_exit(void);
+int dqacq_handler(struct obd_device *obd, struct qunit_data *qdata, int opc);
+int mds_quota_adjust(struct obd_device *obd, unsigned int qcids[],
+ unsigned int qpids[], int rc, int opc);
+int filter_quota_adjust(struct obd_device *obd, unsigned int qcids[],
+ unsigned int qpids[], int rc, int opc);
+int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl);
+int mds_admin_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl);
+int mds_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl);
+int mds_quota_off(struct obd_device *obd, struct obd_quotactl *oqctl);
+int mds_set_dqinfo(struct obd_device *obd, struct obd_quotactl *oqctl);
+int mds_get_dqinfo(struct obd_device *obd, struct obd_quotactl *oqctl);
+int mds_set_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl);
+int mds_get_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl);
+int mds_quota_recovery(struct obd_device *obd);
+int mds_get_obd_quota(struct obd_device *obd, struct obd_quotactl *oqctl);
+#endif
+
+/* quota_ctl.c */
+int mds_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl);
+int filter_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl);
+int client_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl);
+int lov_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl);
+
+/* quota_chk.c */
+int target_quota_check(struct obd_export *exp, struct obd_quotactl *oqctl);
+int client_quota_check(struct obd_export *exp, struct obd_quotactl *oqctl);
+int lov_quota_check(struct obd_export *exp, struct obd_quotactl *oqctl);
+int client_quota_poll_check(struct obd_export *exp, struct if_quotacheck *qchk);
+
+#endif
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
- * lustre/mds/quota_master.c
+ * lustre/quota/quota_master.c
* Lustre Quota Master request handler
*
- * Copyright (c) 2001-2003 Cluster File Systems, Inc.
+ * Copyright (c) 2001-2005 Cluster File Systems, Inc.
* Author: Niu YaWei <niu@clusterfs.com>
*
* This file is part of Lustre, http://www.lustre.org.
#include <linux/lustre_fsfilt.h>
#include <linux/lustre_mds.h>
-#include "mds_internal.h"
+#include "quota_internal.h"
+/* lock ordering:
+ * mds->mds_qonoff_sem > dquot->dq_sem */
static struct list_head lustre_dquot_hash[NR_DQHASH];
static spinlock_t dquot_hash_lock = SPIN_LOCK_UNLOCKED;
LASSERT(list_empty(lustre_dquot_hash + i));
}
if (lustre_dquot_cachep) {
- LASSERTF(kmem_cache_destroy(lustre_dquot_cachep) == 0,
- "Cannot destroy lustre_dquot_cache\n");
+ int rc;
+ rc = kmem_cache_destroy(lustre_dquot_cachep);
+ LASSERT(rc == 0);
lustre_dquot_cachep = NULL;
}
EXIT;
return tmp;
}
+/* caller must hold dquot_hash_lock */
static struct lustre_dquot *find_dquot(int hashent,
struct lustre_quota_info *lqi, qid_t id,
int type)
{
- struct list_head *head;
struct lustre_dquot *dquot;
ENTRY;
- for (head = lustre_dquot_hash[hashent].next;
- head != lustre_dquot_hash + hashent; head = head->next) {
- dquot = list_entry(head, struct lustre_dquot, dq_hash);
+ LASSERT_SPIN_LOCKED(&dquot_hash_lock);
+ list_for_each_entry(dquot, &lustre_dquot_hash[hashent], dq_hash) {
if (dquot->dq_info == lqi &&
dquot->dq_id == id && dquot->dq_type == type)
RETURN(dquot);
RETURN(NULL);
INIT_LIST_HEAD(&dquot->dq_hash);
- INIT_LIST_HEAD(&dquot->dq_unused);
- sema_init(&dquot->dq_sem, 1);
- atomic_set(&dquot->dq_refcnt, 1);
+ init_mutex_locked(&dquot->dq_sem);
+ dquot->dq_refcnt = 1;
dquot->dq_info = lqi;
dquot->dq_id = id;
dquot->dq_type = type;
+ dquot->dq_status = DQ_STATUS_AVAIL;
RETURN(dquot);
}
{
struct list_head *head = lustre_dquot_hash +
dquot_hashfn(dquot->dq_info, dquot->dq_id, dquot->dq_type);
+ LASSERT(list_empty(&dquot->dq_hash));
list_add(&dquot->dq_hash, head);
}
{
ENTRY;
spin_lock(&dquot_hash_lock);
- LASSERT(atomic_read(&dquot->dq_refcnt));
- if (atomic_dec_and_test(&dquot->dq_refcnt)) {
+ LASSERT(dquot->dq_refcnt);
+ dquot->dq_refcnt--;
+ if (!dquot->dq_refcnt) {
remove_dquot_nolock(dquot);
free_dquot(dquot);
}
EXIT;
}
-#define DQUOT_DEBUG(dquot, fmt, arg...) \
- CDEBUG(D_QUOTA, "refcnt(%u) id(%u) type(%u) off(%llu) flags(%lu) " \
- "bhardlimit(%u) curspace("LPX64") ihardlimit(%u) " \
- "curinodes(%u): " fmt, atomic_read(&dquot->dq_refcnt), \
- dquot->dq_id, dquot->dq_type, dquot->dq_off, dquot->dq_flags, \
- dquot->dq_dqb.dqb_bhardlimit, dquot->dq_dqb.dqb_curspace, \
- dquot->dq_dqb.dqb_ihardlimit, dquot->dq_dqb.dqb_curinodes, \
- ## arg); \
-
-#define QINFO_DEBUG(qinfo, fmt, arg...) \
- CDEBUG(D_QUOTA, "files (%p/%p) flags(%lu/%lu) blocks(%u/%u) " \
- "free_blk(/%u/%u) free_entry(%u/%u): " fmt, \
- qinfo->qi_files[0], qinfo->qi_files[1], \
- qinfo->qi_info[0].dqi_flags, qinfo->qi_info[1].dqi_flags, \
- qinfo->qi_info[0].dqi_blocks, qinfo->qi_info[1].dqi_blocks, \
- qinfo->qi_info[0].dqi_free_blk, qinfo->qi_info[1].dqi_free_blk,\
- qinfo->qi_info[0].dqi_free_entry, \
- qinfo->qi_info[1].dqi_free_entry, ## arg);
-
static struct lustre_dquot *lustre_dqget(struct obd_device *obd,
struct lustre_quota_info *lqi,
qid_t id, int type)
{
unsigned int hashent = dquot_hashfn(lqi, id, type);
- struct lustre_dquot *dquot = NULL;
- int read = 0;
+ struct lustre_dquot *dquot, *empty;
ENTRY;
+ if ((empty = alloc_dquot(lqi, id, type)) == NULL)
+ RETURN(ERR_PTR(-ENOMEM));
+
spin_lock(&dquot_hash_lock);
if ((dquot = find_dquot(hashent, lqi, id, type)) != NULL) {
- atomic_inc(&dquot->dq_refcnt);
+ dquot->dq_refcnt++;
+ spin_unlock(&dquot_hash_lock);
+ free_dquot(empty);
} else {
- dquot = alloc_dquot(lqi, id, type);
- if (dquot) {
- insert_dquot_nolock(dquot);
- read = 1;
- }
- }
- spin_unlock(&dquot_hash_lock);
-
- if (dquot == NULL)
- RETURN(ERR_PTR(-ENOMEM));
+ int rc;
- if (read) {
- int rc = 0;
+ dquot = empty;
+ insert_dquot_nolock(dquot);
+ spin_unlock(&dquot_hash_lock);
- down(&dquot->dq_info->qi_sem);
- down(&dquot->dq_sem);
rc = fsfilt_dquot(obd, dquot, QFILE_RD_DQUOT);
up(&dquot->dq_sem);
- up(&dquot->dq_info->qi_sem);
if (rc) {
- CERROR("can't read dquot from admin qutoafile! "
+ CERROR("can't read dquot from admin quotafile! "
"(rc:%d)\n", rc);
lustre_dqput(dquot);
RETURN(ERR_PTR(rc));
}
+
}
+
+ LASSERT(dquot);
RETURN(dquot);
}
int rc = 0;
ENTRY;
+ OBD_FAIL_RETURN(OBD_FAIL_OBD_DQACQ, -EIO);
+
/* slaves never acquires qunit for user root */
LASSERT(qdata->qd_id || qdata->qd_type == GRPQUOTA);
DQUOT_DEBUG(dquot, "get dquot in dqacq_handler\n");
QINFO_DEBUG(dquot->dq_info, "get dquot in dqadq_handler\n");
- down(&dquot->dq_info->qi_sem);
+ down(&mds->mds_qonoff_sem);
down(&dquot->dq_sem);
+ if (dquot->dq_status & DQ_STATUS_RECOVERY) {
+ DQUOT_DEBUG(dquot, "this dquot is under recovering.\n");
+ GOTO(out, rc = -EBUSY);
+ }
+
if (qdata->qd_isblk) {
grace = info->qi_info[qdata->qd_type].dqi_bgrace;
usage = &dquot->dq_dqb.dqb_curspace;
hlimit = dquot->dq_dqb.dqb_ihardlimit;
slimit = dquot->dq_dqb.dqb_isoftlimit;
time = &dquot->dq_dqb.dqb_itime;
- }
+ }
/* if the quota limit in admin quotafile is zero, we just inform
* slave to clear quota limit with zero qd_count */
qdata->qd_count = 0;
GOTO(out, rc);
}
-
- if (opc == QUOTA_DQACQ) {
+
+ switch (opc) {
+ case QUOTA_DQACQ:
if (hlimit &&
QUSG(*usage + qdata->qd_count, qdata->qd_isblk) > hlimit)
GOTO(out, rc = -EDQUOT);
if (slimit &&
QUSG(*usage + qdata->qd_count, qdata->qd_isblk) > slimit) {
- if (*time && CURRENT_SECONDS >= *time)
+ if (*time && cfs_time_current_sec() >= *time)
GOTO(out, rc = -EDQUOT);
else if (!*time)
- *time = CURRENT_SECONDS + grace;
+ *time = cfs_time_current_sec() + grace;
}
*usage += qdata->qd_count;
-
- } else if (opc == QUOTA_DQREL) {
- LASSERT(*usage - qdata->qd_count >= 0);
- *usage -= qdata->qd_count;
+ break;
+ case QUOTA_DQREL:
+ /* The usage in administrative file might be incorrect before
+ * recovery done */
+ if (*usage - qdata->qd_count < 0)
+ *usage = 0;
+ else
+ *usage -= qdata->qd_count;
/* (usage <= soft limit) but not (usage < soft limit) */
if (!slimit || QUSG(*usage, qdata->qd_isblk) <= slimit)
*time = 0;
- } else {
+ break;
+ default:
LBUG();
}
rc = fsfilt_dquot(obd, dquot, QFILE_WR_DQUOT);
+ EXIT;
out:
up(&dquot->dq_sem);
- up(&dquot->dq_info->qi_sem);
+ up(&mds->mds_qonoff_sem);
lustre_dqput(dquot);
- RETURN(rc);
+ return rc;
}
-void mds_adjust_qunit(struct obd_device *obd, uid_t cuid, gid_t cgid,
- uid_t puid, gid_t pgid, int rc)
+int mds_quota_adjust(struct obd_device *obd, unsigned int qcids[],
+ unsigned int qpids[], int rc, int opc)
{
- struct mds_obd *mds = &obd->u.mds;
- struct lustre_quota_ctxt *qctxt = &mds->mds_quota_ctxt;
+ struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
+ int rc2 = 0;
ENTRY;
- if (rc && rc != -EDQUOT) {
- EXIT;
- return;
+ if (rc && rc != -EDQUOT)
+ RETURN(0);
+
+ switch (opc) {
+ case FSFILT_OP_RENAME:
+ /* acquire/release block quota on owner of original parent */
+ rc = qctxt_adjust_qunit(obd, qctxt, qpids[2], qpids[3], 1, 0);
+ /* fall-through */
+ case FSFILT_OP_CREATE:
+ case FSFILT_OP_UNLINK:
+ /* acquire/release file quota on owner of child, acquire/release
+ * block quota on owner of parent */
+ rc = qctxt_adjust_qunit(obd, qctxt, qcids[0], qcids[1], 0, 0);
+ rc2 = qctxt_adjust_qunit(obd, qctxt, qpids[0], qpids[1], 1, 0);
+ break;
+ case FSFILT_OP_SETATTR:
+ /* acquire/release file quota on original & current owner
+ * of child*/
+ rc = qctxt_adjust_qunit(obd, qctxt, qcids[0], qcids[1], 0, 0);
+ rc2 = qctxt_adjust_qunit(obd, qctxt, qpids[0], qpids[1], 0, 0);
+ break;
+ default:
+ LBUG();
+ break;
}
- /* dqacq/dqrel file quota on owner of child */
- rc = qctxt_adjust_qunit(obd, qctxt, cuid, cgid, 0);
- if (rc)
- CERROR("error mds adjust child qunit! (rc:%d)\n", rc);
- /* dqacq/dqrel block quota on owner of parent directory */
- rc = qctxt_adjust_qunit(obd, qctxt, puid, pgid, 1);
- if (rc)
- CERROR("error mds adjust parent qunit! (rc:%d)\n", rc);
- EXIT;
+
+ if (rc || rc2)
+ CERROR("mds adjust qunit failed! (opc:%d rc:%d)\n",
+ opc, rc ?: rc2);
+ RETURN(0);
}
+int filter_quota_adjust(struct obd_device *obd, unsigned int qcids[],
+ unsigned int qpids[], int rc, int opc)
+{
+ struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
+ int rc2 = 0;
+ ENTRY;
+
+ if (rc && rc != -EDQUOT)
+ RETURN(0);
+
+ switch (opc) {
+ case FSFILT_OP_SETATTR:
+ /* acquire/release block quota on original & current owner */
+ rc = qctxt_adjust_qunit(obd, qctxt, qcids[0], qcids[1], 1, 0);
+ rc2 = qctxt_adjust_qunit(obd, qctxt, qpids[0], qpids[1], 1, 0);
+ break;
+ case FSFILT_OP_UNLINK:
+ /* release block quota on this owner */
+ case FSFILT_OP_CREATE: /* XXX for write operation on obdfilter */
+ /* acquire block quota on this owner */
+ rc = qctxt_adjust_qunit(obd, qctxt, qcids[0], qcids[1], 1, 0);
+ break;
+ default:
+ LBUG();
+ break;
+ }
+
+ if (rc || rc2)
+ CERROR("filter adjust qunit failed! (opc:%d rc%d)\n",
+ opc, rc ?: rc2);
+ RETURN(0);
+}
+
+#define LUSTRE_ADMIN_QUOTAFILES {\
+ "admin_quotafile.usr", /* user admin quotafile */\
+ "admin_quotafile.grp" /* group admin quotafile */\
+}
+static const char prefix[] = "OBJECTS/";
+
int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl)
{
struct mds_obd *mds = &obd->u.mds;
LASSERT(iparent);
push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
- down(&qinfo->qi_sem);
+ down(&mds->mds_qonoff_sem);
for (i = 0; i < MAXQUOTAS; i++) {
- struct dentry *de = NULL;
- struct file *fp = NULL;
+ struct dentry *de;
+ struct file *fp;
if (!Q_TYPESET(oqctl, i))
continue;
/* lookup quota file */
rc = 0;
down(&iparent->i_sem);
-
de = lookup_one_len(quotafiles[i], dparent,
strlen(quotafiles[i]));
- if (IS_ERR(de) || de->d_inode == NULL)
+ up(&iparent->i_sem);
+ if (IS_ERR(de) || de->d_inode == NULL ||
+ !S_ISREG(de->d_inode->i_mode))
rc = IS_ERR(de) ? PTR_ERR(de) : -ENOENT;
if (!IS_ERR(de))
dput(de);
- up(&iparent->i_sem);
if (rc && rc != -ENOENT) {
CERROR("error lookup quotafile %s! (rc:%d)\n",
continue;
}
- sprintf(name, "OBJECTS/%s", quotafiles[i]);
+ LASSERT(strlen(quotafiles[i]) + sizeof(prefix) <= sizeof(name));
+ sprintf(name, "%s%s", prefix, quotafiles[i]);
LASSERT(rc == -ENOENT);
/* create quota file */
fp = filp_open(name, O_CREAT | O_EXCL, 0644);
- if (IS_ERR(fp)) {
+ if (IS_ERR(fp) || !S_ISREG(fp->f_dentry->d_inode->i_mode)) {
rc = PTR_ERR(fp);
CERROR("error creating admin quotafile %s (rc:%d)\n",
name, rc);
}
qinfo->qi_files[i] = fp;
- rc = fsfilt_quotainfo(obd, qinfo, i, QFILE_INIT_INFO);
+ rc = fsfilt_quotainfo(obd, qinfo, i, QFILE_INIT_INFO, NULL);
filp_close(fp, 0);
qinfo->qi_files[i] = NULL;
break;
}
}
- up(&qinfo->qi_sem);
+ up(&mds->mds_qonoff_sem);
pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
RETURN(rc);
}
-int mds_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl)
+static int close_quota_files(struct obd_quotactl *oqctl,
+ struct lustre_quota_info *qinfo)
+{
+ int i, rc = 0;
+ ENTRY;
+
+ for (i = 0; i < MAXQUOTAS; i++) {
+ if (!Q_TYPESET(oqctl, i))
+ continue;
+ if (qinfo->qi_files[i] == NULL) {
+ rc = -ESRCH;
+ continue;
+ }
+ filp_close(qinfo->qi_files[i], 0);
+ qinfo->qi_files[i] = NULL;
+ }
+ RETURN(rc);
+}
+
+int mds_admin_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl)
{
struct mds_obd *mds = &obd->u.mds;
struct lustre_quota_info *qinfo = &mds->mds_quota_info;
const char *quotafiles[] = LUSTRE_ADMIN_QUOTAFILES;
- struct lvfs_run_ctxt saved;
char name[64];
int i, rc = 0;
struct inode *iparent = mds->mds_objects_dir->d_inode;
ENTRY;
LASSERT(iparent);
- push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
- down(&qinfo->qi_sem);
/* open admin quota files and read quotafile info */
for (i = 0; i < MAXQUOTAS; i++) {
- struct file *fp = NULL;
+ struct file *fp;
if (!Q_TYPESET(oqctl, i))
continue;
- sprintf(name, "OBJECTS/%s", quotafiles[i]);
+ LASSERT(strlen(quotafiles[i]) + sizeof(prefix) <= sizeof(name));
+ sprintf(name, "%s%s", prefix, quotafiles[i]);
if (qinfo->qi_files[i] != NULL) {
rc = -EBUSY;
}
fp = filp_open(name, O_RDWR | O_EXCL, 0644);
- if (IS_ERR(fp)) {
+ if (IS_ERR(fp) || !S_ISREG(fp->f_dentry->d_inode->i_mode)) {
rc = PTR_ERR(fp);
CERROR("error open %s! (rc:%d)\n", name, rc);
break;
}
qinfo->qi_files[i] = fp;
- rc = fsfilt_quotainfo(obd, qinfo, i, QFILE_RD_INFO);
+ rc = fsfilt_quotainfo(obd, qinfo, i, QFILE_RD_INFO, NULL);
if (rc) {
CERROR("error read quotainfo of %s! (rc:%d)\n",
name, rc);
break;
}
}
- up(&qinfo->qi_sem);
- pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+ if (rc && rc != -EBUSY)
+ close_quota_files(oqctl, qinfo);
- if (rc && rc != -EBUSY) {
- down(&qinfo->qi_sem);
- for (i = 0; i < MAXQUOTAS; i++) {
- if (!Q_TYPESET(oqctl, i))
- continue;
- if (qinfo->qi_files[i])
- filp_close(qinfo->qi_files[i], 0);
- qinfo->qi_files[i] = NULL;
- }
- up(&qinfo->qi_sem);
- }
RETURN(rc);
}
-int mds_quota_off(struct obd_device *obd, struct obd_quotactl *oqctl)
+static int mds_admin_quota_off(struct obd_device *obd,
+ struct obd_quotactl *oqctl)
{
struct mds_obd *mds = &obd->u.mds;
struct lustre_quota_info *qinfo = &mds->mds_quota_info;
- int i, rc = 0;
+ int rc;
ENTRY;
- down(&qinfo->qi_sem);
/* close admin quota files */
- for (i = 0; i < MAXQUOTAS; i++) {
- if (!Q_TYPESET(oqctl, i))
- continue;
+ rc = close_quota_files(oqctl, qinfo);
+ RETURN(rc);
+}
- if (qinfo->qi_files[i] == NULL) {
- rc = -ESRCH;
- continue;
- }
- filp_close(qinfo->qi_files[i], 0);
- qinfo->qi_files[i] = NULL;
- }
- up(&qinfo->qi_sem);
+int mds_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl)
+{
+ struct mds_obd *mds = &obd->u.mds;
+ struct lvfs_run_ctxt saved;
+ int rc;
+ ENTRY;
+
+ down(&mds->mds_qonoff_sem);
+ push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+ rc = mds_admin_quota_on(obd, oqctl);
+ if (rc)
+ goto out;
+ rc = obd_quotactl(mds->mds_osc_exp, oqctl);
+ if (rc)
+ goto out;
+
+ rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
+out:
+ pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+ up(&mds->mds_qonoff_sem);
RETURN(rc);
}
+int mds_quota_off(struct obd_device *obd, struct obd_quotactl *oqctl)
+{
+ struct mds_obd *mds = &obd->u.mds;
+ struct lvfs_run_ctxt saved;
+ int rc, rc2;
+ ENTRY;
+
+ down(&mds->mds_qonoff_sem);
+ /* close admin quota files */
+ push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+ mds_admin_quota_off(obd, oqctl);
+
+ rc = obd_quotactl(mds->mds_osc_exp, oqctl);
+ rc2 = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
+
+ pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+ up(&mds->mds_qonoff_sem);
+ RETURN(rc ?: rc2);
+}
+
int mds_set_dqinfo(struct obd_device *obd, struct obd_quotactl *oqctl)
{
struct mds_obd *mds = &obd->u.mds;
struct lustre_quota_info *qinfo = &mds->mds_quota_info;
struct obd_dqinfo *dqinfo = &oqctl->qc_dqinfo;
- int rc = 0;
+ int rc;
ENTRY;
- if (qinfo->qi_files[oqctl->qc_type] == NULL)
- RETURN(-ESRCH);
+ down(&mds->mds_qonoff_sem);
+ if (qinfo->qi_files[oqctl->qc_type] == NULL) {
+ rc = -ESRCH;
+ goto out;
+ }
- down(&qinfo->qi_sem);
qinfo->qi_info[oqctl->qc_type].dqi_bgrace = dqinfo->dqi_bgrace;
qinfo->qi_info[oqctl->qc_type].dqi_igrace = dqinfo->dqi_igrace;
qinfo->qi_info[oqctl->qc_type].dqi_flags = dqinfo->dqi_flags;
- rc = fsfilt_quotainfo(obd, qinfo, oqctl->qc_type, QFILE_WR_INFO);
- up(&qinfo->qi_sem);
+ rc = fsfilt_quotainfo(obd, qinfo, oqctl->qc_type, QFILE_WR_INFO, NULL);
+out:
+ up(&mds->mds_qonoff_sem);
RETURN(rc);
}
struct mds_obd *mds = &obd->u.mds;
struct lustre_quota_info *qinfo = &mds->mds_quota_info;
struct obd_dqinfo *dqinfo = &oqctl->qc_dqinfo;
+ int rc = 0;
ENTRY;
- if (qinfo->qi_files[oqctl->qc_type] == NULL)
- RETURN(-ESRCH);
+ down(&mds->mds_qonoff_sem);
+ if (qinfo->qi_files[oqctl->qc_type] == NULL) {
+ rc = -ESRCH;
+ goto out;
+ }
- down(&qinfo->qi_sem);
dqinfo->dqi_bgrace = qinfo->qi_info[oqctl->qc_type].dqi_bgrace;
dqinfo->dqi_igrace = qinfo->qi_info[oqctl->qc_type].dqi_igrace;
dqinfo->dqi_flags = qinfo->qi_info[oqctl->qc_type].dqi_flags;
- up(&qinfo->qi_sem);
- RETURN(0);
+out:
+ up(&mds->mds_qonoff_sem);
+ RETURN(rc);
}
static int mds_init_slave_ilimits(struct obd_device *obd,
struct obd_quotactl *oqctl)
{
/* XXX: for file limits only adjust local now */
- struct mds_obd *mds = &obd->u.mds;
unsigned int uid = 0, gid = 0;
struct obd_quotactl *ioqc;
int rc;
if (!oqctl->qc_dqblk.dqb_ihardlimit && !oqctl->qc_dqblk.dqb_isoftlimit)
RETURN(0);
- OBD_ALLOC(ioqc, sizeof(*ioqc));
+ OBD_ALLOC_PTR(ioqc);
if (!ioqc)
RETURN(-ENOMEM);
- ioqc->qc_cmd = Q_SETQUOTA;
+ ioqc->qc_cmd = Q_INITQUOTA;
ioqc->qc_id = oqctl->qc_id;
ioqc->qc_type = oqctl->qc_type;
ioqc->qc_dqblk.dqb_valid = QIF_ILIMITS;
ioqc->qc_dqblk.dqb_ihardlimit = MIN_QLIMIT;
/* set local limit to MIN_QLIMIT */
- rc = fsfilt_quotactl(obd, mds->mds_sb, ioqc);
+ rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, ioqc);
if (rc)
GOTO(out, rc);
else
gid = oqctl->qc_id;
- rc = qctxt_adjust_qunit(obd, &mds->mds_quota_ctxt, uid, gid, 0);
+ rc = qctxt_adjust_qunit(obd, &obd->u.obt.obt_qctxt, uid, gid, 0, 0);
if (rc) {
CERROR("error mds adjust local file quota! (rc:%d)\n", rc);
GOTO(out, rc);
}
/* FIXME initialize all slaves in CMD */
+ EXIT;
out:
- OBD_FREE(ioqc, sizeof(*ioqc));
- RETURN(rc);
+ OBD_FREE_PTR(ioqc);
+ return rc;
}
static int mds_init_slave_blimits(struct obd_device *obd,
if (!oqctl->qc_dqblk.dqb_bhardlimit && !oqctl->qc_dqblk.dqb_bsoftlimit)
RETURN(0);
- OBD_ALLOC(ioqc, sizeof(*ioqc));
+ OBD_ALLOC_PTR(ioqc);
if (!ioqc)
RETURN(-ENOMEM);
- ioqc->qc_cmd = Q_SETQUOTA;
+ ioqc->qc_cmd = Q_INITQUOTA;
ioqc->qc_id = oqctl->qc_id;
ioqc->qc_type = oqctl->qc_type;
ioqc->qc_dqblk.dqb_valid = QIF_BLIMITS;
ioqc->qc_dqblk.dqb_bhardlimit = MIN_QLIMIT;
/* set local limit to MIN_QLIMIT */
- rc = fsfilt_quotactl(obd, mds->mds_sb, ioqc);
+ rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, ioqc);
if (rc)
GOTO(out, rc);
else
gid = oqctl->qc_id;
- rc = qctxt_adjust_qunit(obd, &mds->mds_quota_ctxt, uid, gid, 1);
+ rc = qctxt_adjust_qunit(obd, &obd->u.obt.obt_qctxt, uid, gid, 1, 0);
if (rc) {
CERROR("error mds adjust local block quota! (rc:%d)\n", rc);
GOTO(out, rc);
}
/* initialize all slave's limit */
- ioqc->qc_cmd = Q_INITQUOTA;
rc = obd_quotactl(mds->mds_osc_exp, ioqc);
+ EXIT;
out:
- OBD_FREE(ioqc, sizeof(*ioqc));
- RETURN(rc);
+ OBD_FREE_PTR(ioqc);
+ return rc;
}
int mds_set_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl)
time_t btime, itime;
struct lustre_dquot *dquot;
struct obd_dqblk *dqblk = &oqctl->qc_dqblk;
- int rc = 0;
+ int rc;
ENTRY;
+ down(&mds->mds_qonoff_sem);
if (qinfo->qi_files[oqctl->qc_type] == NULL)
- RETURN(-ESRCH);
+ GOTO(out_sem, rc = -ESRCH);
dquot = lustre_dqget(obd, qinfo, oqctl->qc_id, oqctl->qc_type);
if (IS_ERR(dquot))
- RETURN(PTR_ERR(dquot));
+ GOTO(out_sem, rc = PTR_ERR(dquot));
DQUOT_DEBUG(dquot, "get dquot in mds_set_blk\n");
QINFO_DEBUG(dquot->dq_info, "get dquot in mds_set_blk\n");
- down(&dquot->dq_info->qi_sem);
down(&dquot->dq_sem);
+ if (dquot->dq_status) {
+ up(&dquot->dq_sem);
+ lustre_dqput(dquot);
+ GOTO(out_sem, rc = -EBUSY);
+ }
+ dquot->dq_status |= DQ_STATUS_SET;
+
ihardlimit = dquot->dq_dqb.dqb_ihardlimit;
isoftlimit = dquot->dq_dqb.dqb_isoftlimit;
bhardlimit = dquot->dq_dqb.dqb_bhardlimit;
btime = dquot->dq_dqb.dqb_btime;
itime = dquot->dq_dqb.dqb_itime;
+ if (dqblk->dqb_valid & QIF_BTIME)
+ dquot->dq_dqb.dqb_btime = dqblk->dqb_btime;
+ if (dqblk->dqb_valid & QIF_ITIME)
+ dquot->dq_dqb.dqb_itime = dqblk->dqb_itime;
+
if (dqblk->dqb_valid & QIF_BLIMITS) {
dquot->dq_dqb.dqb_bhardlimit = dqblk->dqb_bhardlimit;
dquot->dq_dqb.dqb_bsoftlimit = dqblk->dqb_bsoftlimit;
if (!dquot->dq_dqb.dqb_bhardlimit &&
!dquot->dq_dqb.dqb_bsoftlimit)
dquot->dq_dqb.dqb_curspace = 0;
+
+ /* clear grace time */
+ if (!dqblk->dqb_bsoftlimit ||
+ toqb(dquot->dq_dqb.dqb_curspace) <= dqblk->dqb_bsoftlimit)
+ dquot->dq_dqb.dqb_btime = 0;
+ /* set grace only if user hasn't provided his own */
+ else if (!(dqblk->dqb_valid & QIF_BTIME))
+ dquot->dq_dqb.dqb_btime = cfs_time_current_sec() +
+ qinfo->qi_info[dquot->dq_type].dqi_bgrace;
}
if (dqblk->dqb_valid & QIF_ILIMITS) {
if (!dquot->dq_dqb.dqb_ihardlimit &&
!dquot->dq_dqb.dqb_isoftlimit)
dquot->dq_dqb.dqb_curinodes = 0;
- }
- if (dqblk->dqb_valid & QIF_BTIME)
- dquot->dq_dqb.dqb_btime = dqblk->dqb_btime;
-
- if (dqblk->dqb_valid & QIF_ITIME)
- dquot->dq_dqb.dqb_itime = dqblk->dqb_itime;
+ if (!dqblk->dqb_isoftlimit ||
+ dquot->dq_dqb.dqb_curinodes <= dqblk->dqb_isoftlimit)
+ dquot->dq_dqb.dqb_itime = 0;
+ else if (!(dqblk->dqb_valid & QIF_ITIME))
+ dquot->dq_dqb.dqb_itime = cfs_time_current_sec() +
+ qinfo->qi_info[dquot->dq_type].dqi_igrace;
+ }
rc = fsfilt_dquot(obd, dquot, QFILE_WR_DQUOT);
up(&dquot->dq_sem);
- up(&dquot->dq_info->qi_sem);
- if (rc)
- GOTO(out, rc);
+ if (rc) {
+ CERROR("set limit failed! (rc:%d)\n", rc);
+ goto out;
+ }
+ up(&mds->mds_qonoff_sem);
if (dqblk->dqb_valid & QIF_ILIMITS && !(ihardlimit || isoftlimit)) {
rc = mds_init_slave_ilimits(obd, oqctl);
if (rc) {
CERROR("init slave ilimits failed! (rc:%d)\n", rc);
- GOTO(revoke_out, rc);
+ goto revoke_out;
}
}
rc = mds_init_slave_blimits(obd, oqctl);
if (rc) {
CERROR("init slave blimits failed! (rc:%d)\n", rc);
- GOTO(revoke_out, rc);
+ goto revoke_out;
}
}
+ down(&mds->mds_qonoff_sem);
revoke_out:
if (rc) {
/* cancel previous setting */
- down(&dquot->dq_info->qi_sem);
down(&dquot->dq_sem);
dquot->dq_dqb.dqb_ihardlimit = ihardlimit;
dquot->dq_dqb.dqb_isoftlimit = isoftlimit;
dquot->dq_dqb.dqb_itime = itime;
fsfilt_dquot(obd, dquot, QFILE_WR_DQUOT);
up(&dquot->dq_sem);
- up(&dquot->dq_info->qi_sem);
}
out:
+ down(&dquot->dq_sem);
+ dquot->dq_status &= ~DQ_STATUS_SET;
+ up(&dquot->dq_sem);
lustre_dqput(dquot);
- RETURN(rc);
+ EXIT;
+out_sem:
+ up(&mds->mds_qonoff_sem);
+ return rc;
}
static int mds_get_space(struct obd_device *obd, struct obd_quotactl *oqctl)
{
struct obd_quotactl *soqc;
+ struct lvfs_run_ctxt saved;
int rc;
+ ENTRY;
- OBD_ALLOC(soqc, sizeof(*soqc));
+ OBD_ALLOC_PTR(soqc);
if (!soqc)
RETURN(-ENOMEM);
- soqc->qc_cmd = oqctl->qc_cmd;
+ soqc->qc_cmd = Q_GETOQUOTA;
soqc->qc_id = oqctl->qc_id;
soqc->qc_type = oqctl->qc_type;
rc = obd_quotactl(obd->u.mds.mds_osc_exp, soqc);
+ if (rc)
+ GOTO(out, rc);
oqctl->qc_dqblk.dqb_curspace = soqc->qc_dqblk.dqb_curspace;
- OBD_FREE(soqc, sizeof(*soqc));
+ push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+ soqc->qc_dqblk.dqb_curspace = 0;
+ rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, soqc);
+ pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+
+ if (rc)
+ GOTO(out, rc);
+
+ oqctl->qc_dqblk.dqb_curinodes += soqc->qc_dqblk.dqb_curinodes;
+ oqctl->qc_dqblk.dqb_curspace += soqc->qc_dqblk.dqb_curspace;
+ EXIT;
+out:
+ OBD_FREE_PTR(soqc);
return rc;
}
int rc;
ENTRY;
+ down(&mds->mds_qonoff_sem);
if (qinfo->qi_files[oqctl->qc_type] == NULL)
- RETURN(-ESRCH);
+ GOTO(out, rc = -ESRCH);
dquot = lustre_dqget(obd, qinfo, oqctl->qc_id, oqctl->qc_type);
if (IS_ERR(dquot))
- RETURN(PTR_ERR(dquot));
+ GOTO(out, rc = PTR_ERR(dquot));
down(&dquot->dq_sem);
dqblk->dqb_ihardlimit = dquot->dq_dqb.dqb_ihardlimit;
dqblk->dqb_itime = dquot->dq_dqb.dqb_itime;
up(&dquot->dq_sem);
+ lustre_dqput(dquot);
+
/* the usages in admin quota file is inaccurate */
dqblk->dqb_curinodes = 0;
dqblk->dqb_curspace = 0;
rc = mds_get_space(obd, oqctl);
+ EXIT;
+out:
+ up(&mds->mds_qonoff_sem);
+ return rc;
+}
+
+int mds_get_obd_quota(struct obd_device *obd, struct obd_quotactl *oqctl)
+{
+ struct lvfs_run_ctxt saved;
+ int rc;
+ ENTRY;
+
+ push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+ rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
+ pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+
+ RETURN(rc);
+}
+
+
+/* FIXME we only recovery block limit by now, need recovery inode
+ * limits also after CMD involved in */
+static int
+dquot_recovery(struct obd_device *obd, unsigned int id, unsigned short type)
+{
+ struct mds_obd *mds = &obd->u.mds;
+ struct lustre_quota_info *qinfo= &obd->u.mds.mds_quota_info;
+ struct lustre_dquot *dquot;
+ struct obd_quotactl *qctl;
+ __u64 total_limits = 0;
+ int rc;
+ ENTRY;
+
+ OBD_ALLOC_PTR(qctl);
+ if (qctl == NULL)
+ RETURN(-ENOMEM);
+
+ dquot = lustre_dqget(obd, qinfo, id, type);
+ if (IS_ERR(dquot)) {
+ CERROR("Get dquot failed. (rc:%ld)\n", PTR_ERR(dquot));
+ OBD_FREE_PTR(qctl);
+ RETURN(PTR_ERR(dquot));
+ }
+
+ down(&dquot->dq_sem);
+
+ /* don't recovery the dquot without limits or under setting */
+ if (!(dquot->dq_dqb.dqb_bhardlimit || dquot->dq_dqb.dqb_bsoftlimit) ||
+ dquot->dq_status)
+ GOTO(skip, rc = 0);
+ dquot->dq_status |= DQ_STATUS_RECOVERY;
+
+ up(&dquot->dq_sem);
+
+ /* get real bhardlimit from all slaves. */
+ qctl->qc_cmd = Q_GETOQUOTA;
+ qctl->qc_type = type;
+ qctl->qc_id = id;
+ qctl->qc_stat = QUOTA_RECOVERING;
+ rc = obd_quotactl(obd->u.mds.mds_osc_exp, qctl);
+ if (rc)
+ GOTO(out, rc);
+ total_limits = qctl->qc_dqblk.dqb_bhardlimit;
+
+ /* get real bhardlimit from master */
+ rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, qctl);
+ if (rc)
+ GOTO(out, rc);
+ total_limits += qctl->qc_dqblk.dqb_bhardlimit;
+
+ /* amend the usage of the administrative quotafile */
+ down(&mds->mds_qonoff_sem);
+ down(&dquot->dq_sem);
+
+ dquot->dq_dqb.dqb_curspace = total_limits << QUOTABLOCK_BITS;
+
+ rc = fsfilt_dquot(obd, dquot, QFILE_WR_DQUOT);
+ if (rc)
+ CERROR("write dquot failed! (rc:%d)\n", rc);
+
+ up(&dquot->dq_sem);
+ up(&mds->mds_qonoff_sem);
+ EXIT;
+out:
+ down(&dquot->dq_sem);
+ dquot->dq_status &= ~DQ_STATUS_RECOVERY;
+skip:
+ up(&dquot->dq_sem);
lustre_dqput(dquot);
+ OBD_FREE_PTR(qctl);
+ return rc;
+}
+
+struct qmaster_recov_thread_data {
+ struct obd_device *obd;
+ struct completion comp;
+};
+
+static int qmaster_recovery_main(void *arg)
+{
+ struct qmaster_recov_thread_data *data = arg;
+ struct obd_device *obd = data->obd;
+ unsigned long flags;
+ int rc = 0;
+ unsigned short type;
+ ENTRY;
+
+ lock_kernel();
+ ptlrpc_daemonize();
+
+ SIGNAL_MASK_LOCK(current, flags);
+ sigfillset(¤t->blocked);
+ RECALC_SIGPENDING;
+ SIGNAL_MASK_UNLOCK(current, flags);
+ THREAD_NAME(cfs_curproc_comm(), CFS_CURPROC_COMM_MAX - 1, "%s",
+ "qmaster_recovd");
+ unlock_kernel();
+
+ complete(&data->comp);
+
+ for (type = USRQUOTA; type < MAXQUOTAS; type++) {
+ struct mds_obd *mds = &obd->u.mds;
+ struct lustre_quota_info *qinfo = &mds->mds_quota_info;
+ struct list_head id_list;
+ struct dquot_id *dqid, *tmp;
+
+ down(&mds->mds_qonoff_sem);
+ if (qinfo->qi_files[type] == NULL) {
+ up(&mds->mds_qonoff_sem);
+ continue;
+ }
+ INIT_LIST_HEAD(&id_list);
+ rc = fsfilt_quotainfo(obd, qinfo, type, QFILE_GET_QIDS,
+ &id_list);
+ up(&mds->mds_qonoff_sem);
+
+ if (rc)
+ CERROR("error get ids from admin quotafile.(%d)\n", rc);
+
+ list_for_each_entry_safe(dqid, tmp, &id_list, di_link) {
+ list_del_init(&dqid->di_link);
+ if (rc)
+ goto free;
+
+ rc = dquot_recovery(obd, dqid->di_id, type);
+ if (rc)
+ CERROR("qmaster recovery failed! (id:%d type:%d"
+ " rc:%d)\n", dqid->di_id, type, rc);
+free:
+ kfree(dqid);
+ }
+ }
+ RETURN(rc);
+}
+
+int mds_quota_recovery(struct obd_device *obd)
+{
+ struct lov_obd *lov = &obd->u.mds.mds_osc_obd->u.lov;
+ struct qmaster_recov_thread_data data;
+ int rc = 0;
+ ENTRY;
+
+ spin_lock(&lov->lov_lock);
+ if (lov->desc.ld_tgt_count != lov->desc.ld_active_tgt_count) {
+ CWARN("Not all osts are active, abort quota recovery\n");
+ spin_unlock(&lov->lov_lock);
+ RETURN(rc);
+ }
+ spin_unlock(&lov->lov_lock);
+
+ data.obd = obd;
+ init_completion(&data.comp);
+
+ rc = kernel_thread(qmaster_recovery_main, &data, CLONE_VM|CLONE_FILES);
+ if (rc < 0)
+ CERROR("Cannot start quota recovery thread: rc %d\n", rc);
+
+ wait_for_completion(&data.comp);
RETURN(rc);
}
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
- * Copyright (C) 2003 Cluster File Systems, Inc.
+ * Copyright (C) 2005 Cluster File Systems, Inc.
* Author: Lai Siyao <lsy@clusterfs.com>
*
* This file is part of Lustre, http://www.lustre.org/
{
unsigned long desc_block, desc;
struct ext3_group_desc *gdp;
-
+
desc_block = group / EXT3_DESC_PER_BLOCK(sb);
desc = group % EXT3_DESC_PER_BLOCK(sb);
gdp = (struct ext3_group_desc *)
EXT3_SB(sb)->s_group_desc[desc_block]->b_data;
-
+
return gdp + desc;
}
{
struct ext3_group_desc *desc;
struct buffer_head *bh;
-
+
desc = get_group_desc(sb, group);
bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap));
-
+
return bh;
}
int index, unsigned long ino)
{
struct inode *inode = NULL;
-
+
if (ext3_test_bit(index, bitmap_bh->b_data)) {
CERROR("i: %d, ino: %lu\n", index, ino);
ll_sleep(1);
inode = iget(sb, ino);
}
-
+
return inode;
}
brelse(bitmap_bh);
bitmap_bh = read_inode_bitmap(sb, group);
- if (group == 0)
+ if (group == 0)
CERROR("groups_count: %lu, inodes_per_group: %lu, first_ino: %u, inodes_count: %u\n",
sbi->s_groups_count, sbi->s_inodes_per_group,
sbi->s_first_ino, le32_to_cpu(sbi->s_es->s_inodes_count));
* ------------------------------------------------------------------------- */
static int quotacheck_run_tests(struct obd_device *obd, struct obd_device *tgt)
{
- struct super_block *sb;
int rc;
ENTRY;
- if (!strcmp(tgt->obd_type->typ_name, LUSTRE_MDS_NAME))
- sb = tgt->u.mds.mds_sb;
- else if (!strcmp(tgt->obd_type->typ_name, "obdfilter"))
- sb = tgt->u.filter.fo_sb;
- else {
+ if (strcmp(tgt->obd_type->typ_name, LUSTRE_MDS_NAME) &&
+ !strcmp(tgt->obd_type->typ_name, "obdfilter")) {
CERROR("TARGET OBD should be mds or ost\n");
RETURN(-EINVAL);
}
- rc = quotacheck_test_1(tgt, sb);
+ rc = quotacheck_test_1(tgt, tgt->u.obt.obt_sb);
return rc;
}
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
- * Copyright (C) 2003 Cluster File Systems, Inc.
+ * Copyright (C) 2005 Cluster File Systems, Inc.
* Author: Lai Siyao <lsy@clusterfs.com>
*
* This file is part of Lustre, http://www.lustre.org/
#include <linux/lustre_mds.h>
#include <linux/obd_ost.h>
-char *test_quotafile[] = {"aquotactl.user", "aquotactl.group"};
+static struct obd_quotactl oqctl;
/* Test quotaon */
static int quotactl_test_1(struct obd_device *obd, struct super_block *sb)
{
- struct obd_quotactl oqctl;
int rc;
ENTRY;
oqctl.qc_id = QFMT_LDISKFS;
oqctl.qc_type = UGQUOTA;
rc = fsfilt_quotactl(obd, sb, &oqctl);
- if (rc) {
+ if (rc)
CERROR("1a: quotactl Q_QUOTAON failed: %d\n", rc);
- RETURN(rc);
- }
-
- RETURN(0);
+ RETURN(rc);
}
#if 0 /* set/getinfo not supported, this is for cluster-wide quotas */
/* Test set/getquota */
static int quotactl_test_3(struct obd_device *obd, struct super_block *sb)
{
- struct obd_quotactl oqctl;
int rc;
ENTRY;
/* Test quotaoff */
static int quotactl_test_4(struct obd_device *obd, struct super_block *sb)
{
- struct obd_quotactl oqctl;
int rc;
ENTRY;
int rc;
ENTRY;
- if (!strcmp(tgt->obd_type->typ_name, LUSTRE_MDS_NAME))
- sb = tgt->u.mds.mds_sb;
- else if (!strcmp(tgt->obd_type->typ_name, "obdfilter"))
- sb = tgt->u.filter.fo_sb;
- else {
- CERROR("TARGET OBD should be mds or obdfilter\n");
+ if (strcmp(tgt->obd_type->typ_name, LUSTRE_MDS_NAME) &&
+ !strcmp(tgt->obd_type->typ_name, "obdfilter")) {
+ CERROR("TARGET OBD should be mds or ost\n");
RETURN(-EINVAL);
}
+ sb = tgt->u.obt.obt_sb;
+
push_ctxt(&saved, &tgt->obd_lvfs_ctxt, NULL);
rc = quotactl_test_1(tgt, sb);
pkgexample_SCRIPTS = $(pkgexample_scripts)
noinst_PROGRAMS = openunlink testreq truncate directio openme writeme
noinst_PROGRAMS += tchmod toexcl fsx test_brw openclose createdestroy
-noinst_PROGRAMS += stat createmany statmany multifstat createtest mlink utime
+noinst_PROGRAMS += stat createmany chownmany statmany multifstat createtest mlink utime
noinst_PROGRAMS += opendirunlink opendevunlink unlinkmany fchdir_test checkstat
noinst_PROGRAMS += wantedi statone runas openfile getdents o_directory
noinst_PROGRAMS += small_write multiop sleeptest ll_sparseness_verify cmknod
--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+void usage(char *prog)
+{
+ printf("usage: %s owner filenamefmt count\n", prog);
+ printf(" %s owner filenamefmt start count\n", prog);
+}
+
+int main(int argc, char ** argv)
+{
+ int i, rc = 0, mask = 0;
+ char format[4096], *fmt;
+ char filename[4096];
+ long start, last;
+ long begin = 0, count;
+
+ if (argc < 4 || argc > 5) {
+ usage(argv[0]);
+ return 1;
+ }
+
+ mask = strtol(argv[1], NULL, 0);
+
+ if (strlen(argv[2]) > 4080) {
+ printf("name too long\n");
+ return 1;
+ }
+
+ start = last = time(0);
+
+ if (argc == 4) {
+ count = strtol(argv[3], NULL, 0);
+ if (count < 1) {
+ printf("count must be at least one\n");
+ return 1;
+ }
+ } else {
+ begin = strtol(argv[3], NULL, 0);
+ count = strtol(argv[4], NULL, 0);
+ }
+
+ if (strchr(argv[2], '%')) {
+ fmt = argv[2];
+ } else {
+ sprintf(format, "%s%%d", argv[2]);
+ fmt = format;
+ }
+ for (i = 0; i < count; i++, begin++) {
+ sprintf(filename, fmt, begin);
+ rc = chown(filename, mask, -1);
+ if (rc) {
+ printf("chown (%s) error: %s\n",
+ filename, strerror(errno));
+ rc = errno;
+ break;
+ }
+ if ((i % 10000) == 0) {
+ printf(" - chowned %d (time %ld ; total %ld ; last "
+ "%ld)\n", i, time(0), time(0) - start,
+ time(0) - last);
+ last = time(0);
+ }
+ }
+ printf("total: %d chowns in %ld seconds: %f chowns/second\n", i,
+ time(0) - start, ((float)i / (time(0) - start)));
+
+ return rc;
+}
--- /dev/null
+#!/bin/sh
+
+set -e
+
+LUSTRE=${LUSTRE:-`dirname $0`/..}
+. $LUSTRE/tests/test-framework.sh
+
+init_test_env $@
+
+. ${CONFIG:=$LUSTRE/tests/cfg/local.sh}
+
+ostfailover_HOST=${ostfailover_HOST:-$ost_HOST}
+
+gen_config() {
+ rm -f "$XMLCONFIG"
+ add_mds mds --dev "$MDSDEV" --size "$MDSSIZE"
+ add_lov lov1 mds --stripe_sz $STRIPE_BYTES \
+ --stripe_cnt $STRIPES_PER_OBJ --stripe_pattern 0
+ add_ost ost --lov lov1 --dev $OSTDEV --size $OSTSIZE --failover
+ if [ ! -z "$ostfailover_HOST" ]; then
+ add_ostfailover ost --dev $OSTDEV --size $OSTSIZE
+ fi
+ add_client client mds --lov lov1 --path $MOUNT
+}
+
+cleanup() {
+ # make sure we are using the primary MDS, so the config log will
+ # be able to clean up properly.
+ activeost=`facet_active ost`
+ if [ $activeost != "ost" ]; then
+ fail ost
+ fi
+ zconf_umount `hostname` $MOUNT
+ stop mds ${FORCE} $MDSLCONFARGS
+ stop ost ${FORCE} --dump $TMP/replay-ost-single-`hostname`.log
+}
+
+if [ "$ONLY" == "cleanup" ]; then
+ sysctl -w portals.debug=0
+ FORCE=--force cleanup
+ exit
+fi
+
+build_test_filter
+
+SETUP=${SETUP:-"setup"}
+CLEANUP=${CLEANUP:-"cleanup"}
+
+setup() {
+ gen_config
+
+ start ost --reformat $OSTLCONFARGS
+ [ "$DAEMONFILE" ] && $LCTL debug_daemon start $DAEMONFILE $DAEMONSIZE
+ start mds --reformat $MDSLCONFARGS
+
+ if [ -z "`grep " $MOUNT " /proc/mounts`" ]; then
+ # test "-1" needed during initial client->OST connection
+ log "== test 00: target handle mismatch (bug 5317) === `date +%H:%M:%S`"
+
+ #define OBD_FAIL_OST_ALL_REPLY_NET 0x211
+ do_facet ost "sysctl -w lustre.fail_loc=0x80000211"
+
+ zconf_mount `hostname` $MOUNT && df $MOUNT && pass || error "mount fail"
+ fi
+}
+
+mkdir -p $DIR
+
+$SETUP
+
+LCOUNT=${LCOUNT:-10000}
+
+test_0() {
+ ./createmany -o $DIR/llog-%d $LCOUNT
+ #replay_barrier ost
+}
+run_test 0 "Prepare fileset"
+
+test_1() {
+ ./chownmany 1000 $DIR/llog-%d $LCOUNT
+ sleep 5
+}
+run_test 1 "Do chowns"
+
+test_2() {
+ HALFCOUNT=${HALFCOUNT:-17}
+ ./chownmany 500 $DIR/llog-%d 0 $HALFCOUNT
+ fail ost
+ ./chownmany 500 $DIR/llog-%d $HALFCOUNT $LCOUNT
+ sleep 5
+}
+#run_test 2 "Fail OST during chown"
+
+test_3() {
+ ./unlinkmany $DIR/llog-%d $LCOUNT
+ sleep 2
+ $CHECKSTAT -t file $DIR/llog-* && return 1 || true
+}
+run_test 3 "Remove testset"
+
+equals_msg test complete, cleaning up
+FORCE=--force $CLEANUP
[ "x$MDS_MOUNT_OPTS" != "x" ] &&
MDS_MOUNT_OPTS="--mountfsoptions $MDS_MOUNT_OPTS"
+[ "x$QUOTA_OPTS" != "x" ] &&
+ QUOTA_OPTS="--quota $QUOTA_OPTS"
+
+# configure mds server
${LMC} --add mds --node $HOSTNAME --mds mds1 --fstype $FSTYPE \
- --dev $MDSDEV $MDS_MOUNT_OPTS \
+ --dev $MDSDEV $MDS_MOUNT_OPTS $QUOTA_OPTS\
--size $MDSSIZE $JARG $IARG $MDSOPT || exit 20
[ "x$OST_MOUNT_OPTS" != "x" ] &&
--stripe_cnt $STRIPES_PER_OBJ --stripe_pattern 0 $LOVOPT || exit 20
${LMC} --add ost --node $HOSTNAME --lov lov1 --fstype $FSTYPE \
- --dev $OSTDEV \
+ --dev $OSTDEV $QUOTA_OPTS\
$OST_MOUNT_OPTS --size $OSTSIZE $JARG $OSTOPT || exit 30
# create client config
${LMC} --add net --node $HOSTNAME --nid $HOSTNAME --nettype $NETTYPE || exit 11
${LMC} --add net --node client --nid '*' --nettype $NETTYPE || exit 12
+[ "x$QUOTA_OPTS" != "x" ] &&
+ QUOTA_OPTS="--quota $QUOTA_OPTS"
+
# configure mds server
[ "x$MDS_MOUNT_OPTS" != "x" ] &&
MDS_MOUNT_OPTS="--mountfsoptions $MDS_MOUNT_OPTS"
${LMC} --format --add mds --node $HOSTNAME --mds mds1 --fstype $FSTYPE \
- --dev $MDSDEV $MDS_MOUNT_OPTS --size $MDSSIZE $MDSOPT || exit 20
+ --dev $MDSDEV $MDS_MOUNT_OPTS $QUOTA_OPTS --size $MDSSIZE $MDSOPT || exit 20
# configure ost
${LMC} --add lov --lov lov1 --mds mds1 --stripe_sz $STRIPE_BYTES \
DEVPTR=OSTDEV$num
eval $DEVPTR=${!DEVPTR:=$TMP/$OST-`hostname`}
${LMC} --add ost --node $HOSTNAME --lov lov1 --ost $OST --fstype $FSTYPE \
- --dev ${!DEVPTR} --size $OSTSIZE $JARG $OSTOPT || exit 30
+ --dev ${!DEVPTR} --size $OSTSIZE $JARG $OSTOPT $QUOTA_OPTS|| exit 30
done
+++ /dev/null
-#!/bin/bash
-
-set -e
-#set -vx
-
-SRCDIR=`dirname $0`
-export PATH=$PWD/$SRCDIR:$SRCDIR:$SRCDIR/../utils:$PATH:/sbin
-. $SRCDIR/test-framework.sh
-
-LFS=${LFS:-lfs}
-LCTL=${LCTL:-lctl}
-USER="quota_usr"
-TSTID=${TSTID:-60000}
-RUNAS=${RUNAS:-"runas -u $TSTID"}
-BLK_SZ=1024
-BUNIT_SZ=1000 # 1000 quota blocks
-BTUNE_SZ=500 # 500 quota blocks
-IUNIT_SZ=10 # 10 files
-ITUNE_SZ=5 # 5 files
-MAX_DQ_TIME=604800
-MAX_IQ_TIME=604800
-
-MOUNT="`cat /proc/mounts | grep "lustre" | awk '{print $2}'`"
-if [ -z "$MOUNT" ]; then
- echo "ERROR: lustre not mounted, quit test!"
- exit 1;
-fi
-OSTCOUNT=`cat /proc/fs/lustre/lov/*/activeobd | head -n 1`
-TSTDIR="$MOUNT/quota_dir"
-
-# set_blk_tunables(btune_sz)
-set_blk_tunesz() {
- # set btune size on all obdfilters
- for i in `ls /proc/fs/lustre/obdfilter/*/quota_btune_sz`; do
- echo $(($1 * $BLK_SZ)) > $i
- done
- # set btune size on mds
- for i in `ls /proc/fs/lustre/mds/mds*/quota_btune_sz`; do
- echo $(($1 * $BLK_SZ)) > $i
- done
-}
-
-# se_blk_unitsz(bunit_sz)
-set_blk_unitsz() {
- for i in `ls /proc/fs/lustre/obdfilter/*/quota_bunit_sz`; do
- echo $(($1 * $BLK_SZ)) > $i
- done
- for i in `ls /proc/fs/lustre/mds/mds*/quota_bunit_sz`; do
- echo $(($1 * $BLK_SZ)) > $i
- done
-}
-
-# set_file_tunesz(itune_sz)
-set_file_tunesz() {
- # set iunit and itune size on all obdfilters
- for i in `ls /proc/fs/lustre/obdfilter/*/quota_itune_sz`; do
- echo $1 > $i
- done
- # set iunit and itune size on mds
- for i in `ls /proc/fs/lustre/mds/mds*/quota_itune_sz`; do
- echo $1 > $i
- done
-
-
-}
-# set_file_unitsz(iunit_sz)
-set_file_unitsz() {
- for i in `ls /proc/fs/lustre/obdfilter/*/quota_iunit_sz`; do
- echo $1 > $i
- done;
- for i in `ls /proc/fs/lustre/mds/mds*/quota_iunit_sz`; do
- echo $1 > $i
- done
-}
-
-prepare_test() {
- # create test group
- GRP="`cat /etc/group | grep "$USER" | awk -F: '{print $1}'`"
- if [ -z "$GRP" ]; then
- groupadd -g $TSTID "$USER"
- fi
- TSTID="`cat /etc/group | grep "$USER" | awk -F: '{print $3}'`"
-
- # create test user
- USR="`cat /etc/passwd | grep "$USER" | awk -F: '{print $1}'`"
- if [ -z "$USR" ]; then
- useradd -u $TSTID -g $TSTID -d /tmp "$USER"
- fi
-
- RUNAS="runas -u $TSTID"
-
- # set block tunables
- set_blk_tunesz $BTUNE_SZ
- set_blk_unitsz $BUNIT_SZ
- # set file tunaables
- set_file_tunesz $ITUNE_SZ
- set_file_unitsz $IUNIT_SZ
-
- [ -d $TSTDIR ] || mkdir $TSTDIR
- chmod 777 $TSTDIR
-}
-
-cleanup_test() {
- # restore block tunables to default size
- set_blk_unitsz $((1024 * 100))
- set_blk_tunesz $((1024 * 50))
- # restore file tunables to default size
- set_file_unitsz 5000
- set_file_tunesz 2500
-
- rm -fr $TSTDIR
- # delete test user and group
- userdel "$USER"
-}
-
-# set quota
-test_1() {
- echo "== Enable quota"
- $LFS quotaoff -ug $MOUNT
- $LFS quotacheck -ug $MOUNT
-
- $LFS setquota -u $USER 0 0 0 0 $MOUNT
- $LFS setquota -g $USER 0 0 0 0 $MOUNT
- return 0
-}
-
-# block hard limit (normal use and out of quota)
-test_2() {
- echo "== Block hard limit"
- LIMIT=$(( $BUNIT_SZ * $(($OSTCOUNT + 1)) * 10)) # 10 bunits each sever
- TESTFILE="$TSTDIR/quota_tst20"
-
- echo " User quota (limit: $LIMIT bytes)"
- $LFS setquota -u $USER 0 $LIMIT 0 0 $MOUNT
-
- $RUNAS touch $TESTFILE >/dev/null 2>&1
-
- echo " Write ..."
- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) > /dev/null 2>&1 || error "(usr) write failure, but expect success"
- echo " Done"
- echo " Write out of block quota ..."
- # this time maybe cache write, ignore it's failure
- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) seek=$(($LIMIT/2)) > /dev/null 2>&1 || echo " " > /dev/null
- # flush cache, ensure noquota flag is setted on client
- sync; sleep 1; sync;
- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$LIMIT > /dev/null 2>&1 && error "(usr) write success, but expect EDQUOT"
- echo " EDQUOT"
-
- rm -f $TESTFILE
-
- echo " Group quota (limit: $LIMIT bytes)"
- $LFS setquota -u $USER 0 0 0 0 $MOUNT # clear user limit
- $LFS setquota -g $USER 0 $LIMIT 0 0 $MOUNT
- TESTFILE="$TSTDIR/quota_tst21"
-
- $RUNAS touch $TESTFILE >/dev/null 2>&1
-
- echo " Write ..."
- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) > /dev/null 2>&1 || error "(grp) write failure, but expect success"
- echo " Done"
- echo " Write out of block quota ..."
- # this time maybe cache write, ignore it's failure
- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) seek=$(($LIMIT/2)) > /dev/null 2>&1 || echo " " > /dev/null
- sync; sleep 1; sync;
- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$LIMIT > /dev/null 2>&1 && error "(grp) write success, but expect EDQUOT"
- echo " EDQUOT"
-
- # cleanup
- rm -f $TESTFILE
- $LFS setquota -g $USER 0 0 0 0 $MOUNT
- return 0
-}
-
-# file hard limit (normal use and out of quota)
-test_3() {
- echo "== File hard limit"
- LIMIT=$(($IUNIT_SZ * 10)) # 10 iunits on mds
- TESTFILE="$TSTDIR/quota_tst30"
-
- echo " User quota (limit: $LIMIT files)"
- $LFS setquota -u $USER 0 0 0 $LIMIT $MOUNT
-
- echo " Create $LIMIT files ..."
- for i in `seq ${LIMIT}`; do
- $RUNAS touch ${TESTFILE}_$i > /dev/null 2>&1 || error "(usr) touch failure, but except success"
- done
- echo " Done"
- echo " Create out of file quota ..."
- $RUNAS touch ${TESTFILE}_xxx > /dev/null 2>&1 && error "(usr) touch success, but expect EDQUOT"
- echo " EDQUOT"
-
- for i in `seq ${LIMIT}`; do
- rm -f ${TESTFILE}_$i
- done
-
- echo " Group quota (limit: $LIMIT files)"
- $LFS setquota -u $USER 0 0 0 0 $MOUNT # clear user limit
- $LFS setquota -g $USER 0 0 0 $LIMIT $MOUNT
- TESTFILE="$TSTDIR/quota_tst31"
-
- echo " Create $LIMIT files ..."
- for i in `seq ${LIMIT}`; do
- $RUNAS touch ${TESTFILE}_$i > /dev/null 2>&1 || error "(grp) touch failure, but expect success"
- done
- echo " Done"
- echo " Create out of file quota ..."
- $RUNAS touch ${TESTFILE}_xxx > /dev/null 2>&1 && error "(grp) touch success, but expect EDQUOT"
- echo " EDQUOT"
-
- # cleanup
- for i in `seq ${LIMIT}`; do
- rm -f ${TESTFILE}_$i
- done
- $LFS setquota -g $USER 0 0 0 0 $MOUNT
- return 0
-}
-
-test_block_soft() {
- TESTFILE=$1
- GRACE=$2
- BS=$(($BUNIT_SZ * $BLK_SZ))
-
- echo " Write to exceed soft limit"
- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ >/dev/null 2>&1 || error "write failure, but expect success"
- sync; sleep 1; sync;
-
- echo " Write before timer goes off"
- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$BUNIT_SZ >/dev/null 2>&1 || error "write failure, but expect success"
- sync; sleep 1; sync;
- echo " Done"
-
- echo " Sleep $GRACE seconds ..."
- sleep $GRACE
-
- echo " Write after timer goes off"
- # maybe cache write, ignore.
- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$(($BUNIT_SZ * 2)) >/dev/null 2>&1 || echo " " > /dev/null
- sync; sleep 1; sync;
- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=1 seek=$(($BUNIT_SZ * 3)) >/dev/null 2>&1 && error "write success, but expect EDQUOT"
- echo " EDQUOT"
-
- echo " Unlink file to stop timer"
- rm -f $TESTFILE
- echo " Done"
-
- echo " Write ..."
- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ >/dev/null 2>&1 || error "write failure, but expect success"
- echo " Done"
-
- # cleanup
- rm -f $TESTFILE
-}
-
-# block soft limit (start timer, timer goes off, stop timer)
-test_4() {
- echo "== Block soft limit"
- LIMIT=$(( $BUNIT_SZ * $(($OSTCOUNT + 1)) )) # 1 bunits each sever
- TESTFILE="$TSTDIR/quota_tst40"
- GRACE=10
-
- echo " User quota (soft limit: $LIMIT bytes grace: $GRACE seconds)"
- $LFS setquota -t -u $GRACE $MAX_IQ_TIME $MOUNT
- $LFS setquota -u $USER $LIMIT 0 0 0 $MOUNT
-
- test_block_soft $TESTFILE $GRACE
- $LFS setquota -u $USER 0 0 0 0 $MOUNT
-
- echo " Group quota (soft limit: $LIMIT bytes grace: $GRACE seconds)"
- $LFS setquota -t -g $GRACE $MAX_IQ_TIME $MOUNT
- $LFS setquota -g $USER $LIMIT 0 0 0 $MOUNT
- TESTFILE="$TSTDIR/quota_tst41"
-
- test_block_soft $TESTFILE $GRACE
- $LFS setquota -g $USER 0 0 0 0 $MOUNT
-
- return 0
-}
-
-test_file_soft() {
- TESTFILE=$1
- LIMIT=$2
- GRACE=$3
-
- echo " Create files to exceed soft limit"
- for i in `seq $LIMIT`; do
- $RUNAS touch ${TESTFILE}_$i >/dev/null 2>&1 || error "touch failure, but expect success"
- done
- echo " Done"
-
- echo " Create file before timer goes off"
- $RUNAS touch ${TESTFILE}_before >/dev/null 2>&1 || error "touch before timer goes off failure, but expect success"
- echo " Done"
-
- echo " Sleep $GRACE seconds ..."
- sleep $GRACE
-
- echo " Create file after timer goes off"
- for i in `seq $(($IUNIT_SZ - 1))`; do
- $RUNAS touch ${TESTFILE}_after_$i >/dev/null 2>&1 || error "touch ${TESTFILE}_after_$i failure, but expect success"
- done
- $RUNAS touch ${TESTFILE}_after >/dev/null 2>&1 && error "touch after timer goes off success, but expect EDQUOT"
- echo " EDQUOT"
-
- echo " Unlink files to stop timer"
- for i in `seq $LIMIT`; do
- rm -f ${TESTFILE}_$i >/dev/null 2>&1 || error "rm ${TESTFILE}_$i failure"
- done
- rm -f ${TESTFILE}_before
- for i in `seq $(($IUNIT_SZ - 1))`; do
- rm -f ${TESTFILE}_after_$i >/dev/null 2>&1 || error "rm ${TESTFILE}_after_$i failure"
- done
- echo " Done"
-
- echo " Create file"
- $RUNAS touch ${TESTFILE}_xxx >/dev/null 2>&1 || error "touch after timer stop failure, but expect success"
- echo " Done"
-
- # cleanup
- rm -f ${TESTFILE}_xxx
-}
-
-# file soft limit (start timer, timer goes off, stop timer)
-test_5() {
- echo "== File soft limit"
- LIMIT=$(($IUNIT_SZ * 10)) # 10 iunits on mds
- TESTFILE="$TSTDIR/quota_tst50"
- GRACE=5
-
- echo " User quota (soft limit: $LIMIT files grace: $GRACE seconds)"
- $LFS setquota -t -u $MAX_DQ_TIME $GRACE $MOUNT
- $LFS setquota -u $USER 0 0 $LIMIT 0 $MOUNT
-
- test_file_soft $TESTFILE $LIMIT $GRACE
- $LFS setquota -u $USER 0 0 0 0 $MOUNT
-
- echo " Group quota (soft limit: $LIMIT files grace: $GRACE seconds)"
- $LFS setquota -t -g $MAX_DQ_TIME $GRACE $MOUNT
- $LFS setquota -g $USER 0 0 $LIMIT 0 $MOUNT
- TESTFILE="$TSTDIR/quota_tst51"
-
- test_file_soft $TESTFILE $LIMIT $GRACE
- $LFS setquota -g $USER 0 0 0 0 $MOUNT
-
- # cleanup
- $LFS setquota -t -u $MAX_DQ_TIME $MAX_IQ_TIME $MOUNT
- $LFS setquota -t -g $MAX_DQ_TIME $MAX_IQ_TIME $MOUNT
- return 0
-}
-
-# chown & chgrp (chown & chgrp successfully even out of block/file quota)
-test_6() {
- echo "== Chown/Chgrp ignore quota"
- BLIMIT=$(( $BUNIT_SZ * $((OSTCOUNT + 1)) * 10)) # 10 bunits on each server
- ILIMIT=$(( $IUNIT_SZ * 10 )) # 10 iunits on mds
-
- echo " Set quota limit (0 $BLIMIT 0 $ILIMIT) for $USER.$USER"
- $LFS setquota -u $USER 0 $BLIMIT 0 $ILIMIT $MOUNT
- $LFS setquota -g $USER 0 $BLIMIT 0 $ILIMIT $MOUNT
-
- echo " Create more than $ILIMIT files and alloc more than $BLIMIT blocks ..."
- for i in `seq $(($ILIMIT + 1))`; do
- touch $TSTDIR/quota_tst60_$i > /dev/null 2>&1 || error "touch failure, expect success"
- done
- dd if=/dev/zero of=$TSTDIR/quota_tst60_1 bs=$BLK_SZ count=$(($BLIMIT+1)) > /dev/null 2>&1 || error "write failure, expect success"
-
- echo " Chown files to $USER.$USER ..."
- for i in `seq $(($ILIMIT + 1))`; do
- chown $USER.$USER $TSTDIR/quota_tst60_$i > /dev/null 2>&1 || error "chown failure, but expect success"
- done
-
- # cleanup
- for i in `seq $(($ILIMIT + 1))`; do
- rm -f $TSTDIR/quota_tst60_$i
- done
- $LFS setquota -u $USER 0 0 0 0 $MOUNT
- $LFS setquota -g $USER 0 0 0 0 $MOUNT
- return 0
-}
-
-# block quota acquire & release
-test_7() {
- echo "== Block quota acqurie / release"
-
- if [ $OSTCOUNT -lt 2 ]; then
- echo "WARN: too few osts, skip this test."
- return 0;
- fi
-
- LIMIT=$(($BUNIT_SZ * $(($OSTCOUNT + 1)) * 10)) # 10 bunits per server
- FILEA="$TSTDIR/quota_tst70_a"
- FILEB="$TSTDIR/quota_tst70_b"
-
- echo " Set block limit $LIMIT bytes to $USER.$USER"
- $LFS setquota -u $USER 0 $LIMIT 0 0 $MOUNT
- $LFS setquota -g $USER 0 $LIMIT 0 0 $MOUNT
-
- echo " Create filea on OST0 and fileb on OST1"
- $LFS setstripe $FILEA 65536 0 1
- $LFS setstripe $FILEB 65536 1 1
- chown $USER.$USER $FILEA
- chown $USER.$USER $FILEB
-
- echo " Exceed quota limit ..."
- $RUNAS dd if=/dev/zero of=$FILEB bs=$BLK_SZ count=$(($LIMIT - $BUNIT_SZ * $OSTCOUNT)) >/dev/null 2>&1 || error "write fileb failure, but expect success"
- sync; sleep 1; sync;
- $RUNAS dd if=/dev/zero of=$FILEB bs=$BLK_SZ seek=$LIMIT count=$BUNIT_SZ >/dev/null 2>&1 && error "write fileb success, but expect EDQUOT"
- sync; sleep 1; sync;
- echo " Write to OST0 return EDQUOT"
- # this write maybe cache write, ignore it's failure
- $RUNAS dd if=/dev/zero of=$FILEA bs=$BLK_SZ count=$(($BUNIT_SZ * 2)) >/dev/null 2>&1 || echo " " > /dev/null
- sync; sleep 1; sync;
- $RUNAS dd if=/dev/zero of=$FILEA bs=$BLK_SZ count=$(($BUNIT_SZ * 2)) seek=$(($BUNIT_SZ *2)) >/dev/null 2>&1 && error "write filea success, but expect EDQUOT"
- echo " EDQUOT"
-
- echo " Remove fileb to let OST1 release quota"
- rm -f $FILEB
-
- echo " Write to OST0"
- $RUNAS dd if=/dev/zero of=$FILEA bs=$BLK_SZ count=$(($LIMIT - $BUNIT_SZ * $OSTCOUNT)) >/dev/null 2>&1 || error "write filea failure, expect success"
- echo " Done"
-
- # cleanup
- rm -f $FILEA
- $LFS setquota -u $USER 0 0 0 0 $MOUNT
- $LFS setquota -g $USER 0 0 0 0 $MOUNT
- return 0
-}
-
-# turn off quota
-test_8()
-{
- echo "=== Turn off quota"
- $LFS quotaoff $MOUNT
- return 0
-}
-
-prepare_test
-
-# run all tests
-for j in `seq 8`; do
- test_$j
- echo "== Done"
- echo " "
-done
-
-cleanup_test
--- /dev/null
+#!/bin/bash
+#
+# Run select tests by setting ONLY, or as arguments to the script.
+# Skip specific tests by setting EXCEPT.
+#
+# Run test by setting NOSETUP=true when ltest has setup env for us
+set -e
+
+SRCDIR=`dirname $0`
+export PATH=$PWD/$SRCDIR:$SRCDIR:$PWD/$SRCDIR/../utils:$PATH:/sbin
+
+ONLY=${ONLY:-"$*"}
+ALWAYS_EXCEPT=${ALWAYS_EXCEPT:-""}
+# UPDATE THE COMMENT ABOVE WITH BUG NUMBERS WHEN CHANGING ALWAYS_EXCEPT!
+
+case `uname -r` in
+2.6*) FSTYPE=${FSTYPE:-ldiskfs};;
+*) error "unsupported kernel" ;;
+esac
+
+[ "$ALWAYS_EXCEPT$EXCEPT" ] && \
+ echo "Skipping tests: `echo $ALWAYS_EXCEPT $EXCEPT`"
+
+TMP=${TMP:-/tmp}
+
+LFS=${LFS:-lfs}
+LCTL=${LCTL:-lctl}
+LSTRIPE=${LSTRIPE:-"$LFS setstripe"}
+TSTID=${TSTID:-60000}
+RUNAS=${RUNAS:-"runas -u $TSTID"}
+TSTUSR=${TSTUSR:-"quota_usr"}
+BLK_SZ=1024
+BUNIT_SZ=${BUNIT_SZ:-1000} # default 1000 quota blocks
+BTUNE_SZ=${BTUNE_SZ:-500} # default 50% of BUNIT_SZ
+IUNIT_SZ=${IUNIT_SZ:-10} # default 10 files
+ITUNE_SZ=${ITUNE_SZ:-5} # default 50% of IUNIT_SZ
+MAX_DQ_TIME=604800
+MAX_IQ_TIME=604800
+
+log() {
+ echo "$*"
+ $LCTL mark "$*" 2> /dev/null || true
+}
+
+trace() {
+ log "STARTING: $*"
+ strace -o $TMP/$1.strace -ttt $*
+ RC=$?
+ log "FINISHED: $*: rc $RC"
+ return 1
+}
+TRACE=${TRACE:-""}
+
+run_one() {
+ BEFORE=`date +%s`
+ log "== test $1: $2= `date +%H:%M:%S` ($BEFORE)"
+ export TESTNAME=test_$1
+ test_$1 || error "exit with rc=$?"
+ unset TESTNAME
+ pass "($((`date +%s` - $BEFORE))s)"
+ cd $SAVE_PWD
+}
+
+build_test_filter() {
+ for O in $ONLY; do
+ eval ONLY_${O}=true
+ done
+ for E in $EXCEPT $ALWAYS_EXCEPT; do
+ eval EXCEPT_${E}=true
+ done
+ # turn on/off quota tests must be included
+ eval ONLY_0=true
+ eval ONLY_9=true
+}
+
+_basetest() {
+ echo $*
+}
+
+basetest() {
+ IFS=abcdefghijklmnopqrstuvwxyz _basetest $1
+}
+
+run_test() {
+ base=`basetest $1`
+ if [ "$ONLY" ]; then
+ testname=ONLY_$1
+ if [ ${!testname}x != x ]; then
+ run_one $1 "$2"
+ return $?
+ fi
+ testname=ONLY_$base
+ if [ ${!testname}x != x ]; then
+ run_one $1 "$2"
+ return $?
+ fi
+ echo -n "."
+ return 0
+ fi
+ testname=EXCEPT_$1
+ if [ ${!testname}x != x ]; then
+ echo "skipping excluded test $1"
+ return 0
+ fi
+ testname=EXCEPT_$base
+ if [ ${!testname}x != x ]; then
+ echo "skipping excluded test $1 (base $base)"
+ return 0
+ fi
+ run_one $1 "$2"
+ return $?
+}
+
+[ "$SANITYLOG" ] && rm -f $SANITYLOG || true
+
+error() {
+ sysctl -w lustre.fail_loc=0
+ log "FAIL: $TESTNAME $@"
+ if [ "$SANITYLOG" ]; then
+ echo "FAIL: $TESTNAME $@" >> $SANITYLOG
+ else
+ exit 1
+ fi
+}
+
+pass() {
+ echo PASS $@
+}
+
+mounted_lustre_filesystems() {
+ awk '($3 ~ "lustre") { print $2 }' /proc/mounts
+}
+MOUNT="`mounted_lustre_filesystems`"
+if [ -z "$MOUNT" ]; then
+ export QUOTA_OPTS="quotaon=ug"
+ sh llmount.sh
+ MOUNT="`mounted_lustre_filesystems`"
+ [ -z "$MOUNT" ] && error "NAME=$NAME not mounted"
+ I_MOUNTED=yes
+fi
+
+[ `echo $MOUNT | wc -w` -gt 1 ] && error "NAME=$NAME mounted more than once"
+
+DIR=${DIR:-$MOUNT}
+[ -z "`echo $DIR | grep $MOUNT`" ] && echo "$DIR not in $MOUNT" && exit 99
+
+LPROC=/proc/fs/lustre
+LOVNAME=`cat $LPROC/llite/*/lov/common_name | tail -n 1`
+OSTCOUNT=`cat $LPROC/lov/$LOVNAME/numobd`
+STRIPECOUNT=`cat $LPROC/lov/$LOVNAME/stripecount`
+STRIPESIZE=`cat $LPROC/lov/$LOVNAME/stripesize`
+ORIGFREE=`cat $LPROC/lov/$LOVNAME/kbytesavail`
+MAXFREE=${MAXFREE:-$((200000 * $OSTCOUNT))}
+MDS=$(\ls $LPROC/mds 2> /dev/null | grep -v num_refs | tail -n 1)
+TSTDIR="$MOUNT/quota_dir"
+
+build_test_filter
+
+
+# set_blk_tunables(btune_sz)
+set_blk_tunesz() {
+ # set btune size on all obdfilters
+ for i in `ls /proc/fs/lustre/obdfilter/*/quota_btune_sz`; do
+ echo $(($1 * $BLK_SZ)) > $i
+ done
+ # set btune size on mds
+ for i in `ls /proc/fs/lustre/mds/mds*/quota_btune_sz`; do
+ echo $(($1 * $BLK_SZ)) > $i
+ done
+}
+# se_blk_unitsz(bunit_sz)
+set_blk_unitsz() {
+ for i in `ls /proc/fs/lustre/obdfilter/*/quota_bunit_sz`; do
+ echo $(($1 * $BLK_SZ)) > $i
+ done
+ for i in `ls /proc/fs/lustre/mds/mds*/quota_bunit_sz`; do
+ echo $(($1 * $BLK_SZ)) > $i
+ done
+}
+# set_file_tunesz(itune_sz)
+set_file_tunesz() {
+ # set iunit and itune size on all obdfilters
+ for i in `ls /proc/fs/lustre/obdfilter/*/quota_itune_sz`; do
+ echo $1 > $i
+ done
+ # set iunit and itune size on mds
+ for i in `ls /proc/fs/lustre/mds/mds*/quota_itune_sz`; do
+ echo $1 > $i
+ done
+
+
+}
+# set_file_unitsz(iunit_sz)
+set_file_unitsz() {
+ for i in `ls /proc/fs/lustre/obdfilter/*/quota_iunit_sz`; do
+ echo $1 > $i
+ done;
+ for i in `ls /proc/fs/lustre/mds/mds*/quota_iunit_sz`; do
+ echo $1 > $i
+ done
+}
+
+# These are for test on local machine,if run sanity-quota.sh on
+# real cluster, ltest should have setup the test environment:
+#
+# - create test user/group on all servers with same id.
+# - set unit size/tune on all servers size to reasonable value.
+pre_test() {
+ if [ -z "$NOSETUP" ]; then
+ # set block tunables
+ set_blk_tunesz $BTUNE_SZ
+ set_blk_unitsz $BUNIT_SZ
+ # set file tunaables
+ set_file_tunesz $ITUNE_SZ
+ set_file_unitsz $IUNIT_SZ
+ fi
+}
+pre_test
+
+post_test() {
+ if [ -z "$NOSETUP" ]; then
+ # restore block tunables to default size
+ set_blk_unitsz $((1024 * 100))
+ set_blk_tunesz $((1024 * 50))
+ # restore file tunables to default size
+ set_file_unitsz 5000
+ set_file_tunesz 2500
+ fi
+}
+
+setup() {
+ # create local test group
+ GRP="`cat /etc/group | grep "$TSTUSR" | awk -F: '{print $1}'`"
+ if [ -z "$GRP" ]; then
+ groupadd -g $TSTID "$TSTUSR"
+ fi
+ TSTID="`cat /etc/group | grep "$TSTUSR" | awk -F: '{print $3}'`"
+
+ # create test user
+ USR="`cat /etc/passwd | grep "$TSTUSR" | awk -F: '{print $1}'`"
+ if [ -z "$USR" ]; then
+ useradd -u $TSTID -g $TSTID -d /tmp "$TSTUSR"
+ fi
+
+ RUNAS="runas -u $TSTID"
+
+ # create test directory
+ [ -d $TSTDIR ] || mkdir $TSTDIR
+ chmod 777 $TSTDIR
+}
+setup
+
+# set quota
+test_0() {
+ $LFS quotaoff -ug $MOUNT
+ $LFS quotacheck -ug $MOUNT
+
+ $LFS setquota -u $TSTUSR 0 0 0 0 $MOUNT
+ $LFS setquota -g $TSTUSR 0 0 0 0 $MOUNT
+}
+run_test 0 "Set quota ============================="
+
+# block hard limit (normal use and out of quota)
+test_1() {
+ LIMIT=$(( $BUNIT_SZ * $(($OSTCOUNT + 1)) * 10)) # 10 bunits each sever
+ TESTFILE="$TSTDIR/quota_tst10"
+
+ echo " User quota (limit: $LIMIT bytes)"
+ $LFS setquota -u $TSTUSR 0 $LIMIT 0 0 $MOUNT
+
+ $LFS setstripe $TESTFILE 65536 0 1
+ chown $TSTUSR.$TSTUSR $TESTFILE
+
+ echo " Write ..."
+ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) > /dev/null 2>&1 || error "(usr) write failure, but expect success"
+ echo " Done"
+ echo " Write out of block quota ..."
+ # this time maybe cache write, ignore it's failure
+ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) seek=$(($LIMIT/2)) > /dev/null 2>&1 || echo " " > /dev/null
+ # flush cache, ensure noquota flag is setted on client
+ sync; sleep 1; sync;
+ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$LIMIT > /dev/null 2>&1 && error "(usr) write success, but expect EDQUOT"
+ echo " EDQUOT"
+
+ rm -f $TESTFILE
+
+ echo " Group quota (limit: $LIMIT bytes)"
+ $LFS setquota -u $TSTUSR 0 0 0 0 $MOUNT # clear user limit
+ $LFS setquota -g $TSTUSR 0 $LIMIT 0 0 $MOUNT
+ TESTFILE="$TSTDIR/quota_tst11"
+
+ $LFS setstripe $TESTFILE 65536 0 1
+ chown $TSTUSR.$TSTUSR $TESTFILE
+
+ echo " Write ..."
+ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) > /dev/null 2>&1 || error "(grp) write failure, but expect success"
+ echo " Done"
+ echo " Write out of block quota ..."
+ # this time maybe cache write, ignore it's failure
+ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) seek=$(($LIMIT/2)) > /dev/null 2>&1 || echo " " > /dev/null
+ sync; sleep 1; sync;
+ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$LIMIT > /dev/null 2>&1 && error "(grp) write success, but expect EDQUOT"
+ echo " EDQUOT"
+
+ # cleanup
+ rm -f $TESTFILE
+ $LFS setquota -g $TSTUSR 0 0 0 0 $MOUNT
+}
+run_test 1 "Block hard limit (normal use and out of quota) ==="
+
+# file hard limit (normal use and out of quota)
+test_2() {
+ LIMIT=$(($IUNIT_SZ * 10)) # 10 iunits on mds
+ TESTFILE="$TSTDIR/quota_tstr20"
+
+ echo " User quota (limit: $LIMIT files)"
+ $LFS setquota -u $TSTUSR 0 0 0 $LIMIT $MOUNT
+
+ echo " Create $LIMIT files ..."
+ for i in `seq ${LIMIT}`; do
+ $RUNAS touch ${TESTFILE}_$i > /dev/null 2>&1 || error "(usr) touch failure, but except success"
+ done
+ echo " Done"
+ echo " Create out of file quota ..."
+ $RUNAS touch ${TESTFILE}_xxx > /dev/null 2>&1 && error "(usr) touch success, but expect EDQUOT"
+ echo " EDQUOT"
+
+ for i in `seq ${LIMIT}`; do
+ rm -f ${TESTFILE}_$i
+ done
+
+ echo " Group quota (limit: $LIMIT files)"
+ $LFS setquota -u $TSTUSR 0 0 0 0 $MOUNT # clear user limit
+ $LFS setquota -g $TSTUSR 0 0 0 $LIMIT $MOUNT
+ TESTFILE="$TSTDIR/quota_tst21"
+
+ echo " Create $LIMIT files ..."
+ for i in `seq ${LIMIT}`; do
+ $RUNAS touch ${TESTFILE}_$i > /dev/null 2>&1 || error "(grp) touch failure, but expect success"
+ done
+ echo " Done"
+ echo " Create out of file quota ..."
+ $RUNAS touch ${TESTFILE}_xxx > /dev/null 2>&1 && error "(grp) touch success, but expect EDQUOT"
+ echo " EDQUOT"
+
+ # cleanup
+ for i in `seq ${LIMIT}`; do
+ rm -f ${TESTFILE}_$i
+ done
+ $LFS setquota -g $TSTUSR 0 0 0 0 $MOUNT
+}
+run_test 2 "File hard limit (normal use and out of quota) ==="
+
+test_block_soft() {
+ TESTFILE=$1
+ GRACE=$2
+
+ echo " Write to exceed soft limit"
+ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ >/dev/null 2>&1 || error "write failure, but expect success"
+ sync; sleep 1; sync;
+
+ echo " Write before timer goes off"
+ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$BUNIT_SZ >/dev/null 2>&1 || error "write failure, but expect success"
+ sync; sleep 1; sync;
+ echo " Done"
+
+ echo " Sleep $GRACE seconds ..."
+ sleep $GRACE
+
+ echo " Write after timer goes off"
+ # maybe cache write, ignore.
+ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$(($BUNIT_SZ * 2)) >/dev/null 2>&1 || echo " " > /dev/null
+ sync; sleep 1; sync;
+ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=1 seek=$(($BUNIT_SZ * 3)) >/dev/null 2>&1 && error "write success, but expect EDQUOT"
+ echo " EDQUOT"
+
+ echo " Unlink file to stop timer"
+ rm -f $TESTFILE
+ echo " Done"
+
+ echo " Write ..."
+ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ >/dev/null 2>&1 || error "write failure, but expect success"
+ echo " Done"
+
+ # cleanup
+ rm -f $TESTFILE
+}
+
+# block soft limit (start timer, timer goes off, stop timer)
+test_3() {
+ LIMIT=$(( $BUNIT_SZ * 2 )) # 1 bunit on mds and 1 bunit on the ost
+ GRACE=10
+
+ echo " User quota (soft limit: $LIMIT bytes grace: $GRACE seconds)"
+ TESTFILE="$TSTDIR/quota_tst30"
+ $LFS setstripe $TESTFILE 65536 0 1
+ chown $TSTUSR.$TSTUSR $TESTFILE
+
+ $LFS setquota -t -u $GRACE $MAX_IQ_TIME $MOUNT
+ $LFS setquota -u $TSTUSR $LIMIT 0 0 0 $MOUNT
+
+ test_block_soft $TESTFILE $GRACE
+ $LFS setquota -u $TSTUSR 0 0 0 0 $MOUNT
+
+ echo " Group quota (soft limit: $LIMIT bytes grace: $GRACE seconds)"
+ TESTFILE="$TSTDIR/quota_tst31"
+ $LFS setstripe $TESTFILE 65536 0 1
+ chown $TSTUSR.$TSTUSR $TESTFILE
+
+ $LFS setquota -t -g $GRACE $MAX_IQ_TIME $MOUNT
+ $LFS setquota -g $TSTUSR $LIMIT 0 0 0 $MOUNT
+ TESTFILE="$TSTDIR/quota_tst31"
+
+ test_block_soft $TESTFILE $GRACE
+ $LFS setquota -g $TSTUSR 0 0 0 0 $MOUNT
+}
+run_test 3 "Block soft limit (start timer, timer goes off, stop timer) ==="
+
+test_file_soft() {
+ TESTFILE=$1
+ LIMIT=$2
+ GRACE=$3
+
+ echo " Create files to exceed soft limit"
+ for i in `seq $LIMIT`; do
+ $RUNAS touch ${TESTFILE}_$i >/dev/null 2>&1 || error "touch failure, but expect success"
+ done
+ echo " Done"
+
+ echo " Create file before timer goes off"
+ $RUNAS touch ${TESTFILE}_before >/dev/null 2>&1 || error "touch before timer goes off failure, but expect success"
+ echo " Done"
+
+ echo " Sleep $GRACE seconds ..."
+ sleep $GRACE
+
+ echo " Create file after timer goes off"
+ for i in `seq $(($IUNIT_SZ - 1))`; do
+ $RUNAS touch ${TESTFILE}_after_$i >/dev/null 2>&1 || error "touch ${TESTFILE}_after_$i failure, but expect success"
+ done
+ $RUNAS touch ${TESTFILE}_after >/dev/null 2>&1 && error "touch after timer goes off success, but expect EDQUOT"
+ echo " EDQUOT"
+
+ echo " Unlink files to stop timer"
+ for i in `seq $LIMIT`; do
+ rm -f ${TESTFILE}_$i >/dev/null 2>&1 || error "rm ${TESTFILE}_$i failure"
+ done
+ rm -f ${TESTFILE}_before
+ for i in `seq $(($IUNIT_SZ - 1))`; do
+ rm -f ${TESTFILE}_after_$i >/dev/null 2>&1 || error "rm ${TESTFILE}_after_$i failure"
+ done
+ echo " Done"
+
+ echo " Create file"
+ $RUNAS touch ${TESTFILE}_xxx >/dev/null 2>&1 || error "touch after timer stop failure, but expect success"
+ echo " Done"
+
+ # cleanup
+ rm -f ${TESTFILE}_xxx
+}
+
+# file soft limit (start timer, timer goes off, stop timer)
+test_4() {
+ LIMIT=$(($IUNIT_SZ * 10)) # 10 iunits on mds
+ TESTFILE="$TSTDIR/quota_tst40"
+ GRACE=5
+
+ echo " User quota (soft limit: $LIMIT files grace: $GRACE seconds)"
+ $LFS setquota -t -u $MAX_DQ_TIME $GRACE $MOUNT
+ $LFS setquota -u $TSTUSR 0 0 $LIMIT 0 $MOUNT
+
+ test_file_soft $TESTFILE $LIMIT $GRACE
+ $LFS setquota -u $TSTUSR 0 0 0 0 $MOUNT
+
+ echo " Group quota (soft limit: $LIMIT files grace: $GRACE seconds)"
+ $LFS setquota -t -g $MAX_DQ_TIME $GRACE $MOUNT
+ $LFS setquota -g $TSTUSR 0 0 $LIMIT 0 $MOUNT
+ TESTFILE="$TSTDIR/quota_tst41"
+
+ test_file_soft $TESTFILE $LIMIT $GRACE
+ $LFS setquota -g $TSTUSR 0 0 0 0 $MOUNT
+
+ # cleanup
+ $LFS setquota -t -u $MAX_DQ_TIME $MAX_IQ_TIME $MOUNT
+ $LFS setquota -t -g $MAX_DQ_TIME $MAX_IQ_TIME $MOUNT
+}
+run_test 4 "File soft limit (start timer, timer goes off, stop timer) ==="
+
+# chown & chgrp (chown & chgrp successfully even out of block/file quota)
+test_5() {
+ BLIMIT=$(( $BUNIT_SZ * $((OSTCOUNT + 1)) * 10)) # 10 bunits on each server
+ ILIMIT=$(( $IUNIT_SZ * 10 )) # 10 iunits on mds
+
+ echo " Set quota limit (0 $BLIMIT 0 $ILIMIT) for $TSTUSR.$TSTUSR"
+ $LFS setquota -u $TSTUSR 0 $BLIMIT 0 $ILIMIT $MOUNT
+ $LFS setquota -g $TSTUSR 0 $BLIMIT 0 $ILIMIT $MOUNT
+
+ echo " Create more than $ILIMIT files and alloc more than $BLIMIT blocks ..."
+ for i in `seq $(($ILIMIT + 1))`; do
+ touch $TSTDIR/quota_tst50_$i > /dev/null 2>&1 || error "touch failure, expect success"
+ done
+ dd if=/dev/zero of=$TSTDIR/quota_tst50_1 bs=$BLK_SZ count=$(($BLIMIT+1)) > /dev/null 2>&1 || error "write failure, expect success"
+
+ echo " Chown files to $TSTUSR.$TSTUSR ..."
+ for i in `seq $(($ILIMIT + 1))`; do
+ chown $TSTUSR.$TSTUSR $TSTDIR/quota_tst50_$i > /dev/null 2>&1 || error "chown failure, but expect success"
+ done
+
+ # cleanup
+ for i in `seq $(($ILIMIT + 1))`; do
+ rm -f $TSTDIR/quota_tst50_$i
+ done
+ $LFS setquota -u $TSTUSR 0 0 0 0 $MOUNT
+ $LFS setquota -g $TSTUSR 0 0 0 0 $MOUNT
+}
+run_test 5 "Chown & chgrp (chown & chgrp successfully even out of block/file quota) ==="
+
+# block quota acquire & release
+test_6() {
+ if [ $OSTCOUNT -lt 2 ]; then
+ echo "WARN: too few osts, skip this test."
+ return 0;
+ fi
+
+ LIMIT=$(($BUNIT_SZ * $(($OSTCOUNT + 1)) * 10)) # 10 bunits per server
+ FILEA="$TSTDIR/quota_tst60_a"
+ FILEB="$TSTDIR/quota_tst60_b"
+
+ echo " Set block limit $LIMIT bytes to $TSTUSR.$TSTUSR"
+ $LFS setquota -u $TSTUSR 0 $LIMIT 0 0 $MOUNT
+ $LFS setquota -g $TSTUSR 0 $LIMIT 0 0 $MOUNT
+
+ echo " Create filea on OST0 and fileb on OST1"
+ $LFS setstripe $FILEA 65536 0 1
+ $LFS setstripe $FILEB 65536 1 1
+ chown $TSTUSR.$TSTUSR $FILEA
+ chown $TSTUSR.$TSTUSR $FILEB
+
+ echo " Exceed quota limit ..."
+ $RUNAS dd if=/dev/zero of=$FILEB bs=$BLK_SZ count=$(($LIMIT - $BUNIT_SZ * $OSTCOUNT)) >/dev/null 2>&1 || error "write fileb failure, but expect success"
+ sync; sleep 1; sync;
+ $RUNAS dd if=/dev/zero of=$FILEB bs=$BLK_SZ seek=$LIMIT count=$BUNIT_SZ >/dev/null 2>&1 && error "write fileb success, but expect EDQUOT"
+ sync; sleep 1; sync;
+ echo " Write to OST0 return EDQUOT"
+ # this write maybe cache write, ignore it's failure
+ $RUNAS dd if=/dev/zero of=$FILEA bs=$BLK_SZ count=$(($BUNIT_SZ * 2)) >/dev/null 2>&1 || echo " " > /dev/null
+ sync; sleep 1; sync;
+ $RUNAS dd if=/dev/zero of=$FILEA bs=$BLK_SZ count=$(($BUNIT_SZ * 2)) seek=$(($BUNIT_SZ *2)) >/dev/null 2>&1 && error "write filea success, but expect EDQUOT"
+ echo " EDQUOT"
+
+ echo " Remove fileb to let OST1 release quota"
+ rm -f $FILEB
+
+ echo " Write to OST0"
+ $RUNAS dd if=/dev/zero of=$FILEA bs=$BLK_SZ count=$(($LIMIT - $BUNIT_SZ * $OSTCOUNT)) >/dev/null 2>&1 || error "write filea failure, expect success"
+ echo " Done"
+
+ # cleanup
+ rm -f $FILEA
+ $LFS setquota -u $TSTUSR 0 0 0 0 $MOUNT
+ $LFS setquota -g $TSTUSR 0 0 0 0 $MOUNT
+ return 0
+}
+run_test 6 "Block quota acquire & release ========="
+
+# quota recovery (block quota only by now)
+test_7()
+{
+ if [ -z "`lsmod|grep mds`" ]; then
+ echo "WARN: no local mds, skip this test"
+ return 0
+ fi
+
+ LIMIT=$(( $BUNIT_SZ * $(($OSTCOUNT + 1)) * 10)) # 10 bunits each sever
+ TESTFILE="$TSTDIR/quota_tst70"
+
+ $LFS setquota -u $TSTUSR 0 $LIMIT 0 0 $MOUNT
+
+ $LFS setstripe $TESTFILE 65536 0 1
+ chown $TSTUSR.$TSTUSR $TESTFILE
+
+ echo " Write to OST0..."
+ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ >/dev/null 2>&1 || error "write failure, but expect success"
+
+ #define OBD_FAIL_OBD_DQACQ 0x604
+ echo 0x604 > /proc/sys/lustre/fail_loc
+ echo " Remove files on OST0"
+ rm -f $TESTFILE
+ echo 0 > /proc/sys/lustre/fail_loc
+
+ echo " Trigger recovery..."
+ OSC0_UUID="`$LCTL dl | awk '/.* OSC_[^ ]+_OST.* / { print $1 }'`"
+ [ -z "$OSC0_UUID" ] && OSC0_UUID="`$LCTL dl | awk '/.* OSC_[^ ]+_ost1.* / { print $1 }'`"
+ for i in $OSC0_UUID; do
+ $LCTL --device $i activate > /dev/null 2>&1 || error "activate osc failed!"
+ done
+
+ # sleep a while to wait for recovery done
+ sleep 20
+
+ # check limits
+ PATTERN="`echo $MOUNT | sed 's/\//\\\\\//g'`"
+ TOTAL_LIMIT="`$LFS quota -u $TSTUSR $MOUNT | awk '/^.*'$PATTERN'.*[[:digit:]+][[:space:]+]/ { print $4 }'`"
+ [ $TOTAL_LIMIT -eq $LIMIT ] || error "total limits not recovery!"
+ echo " total limits = $TOTAL_LIMIT"
+
+ OST0_UUID=`$LCTL dl | awk '/.*OST_[^ ]+_UUID.* / { print $5 }'`
+ [ -z "$OST0_UUID" ] && OST0_UUID=`$LCTL dl | awk '/.*ost1_[^ ]*UUID.* / { print $5 }'`
+ OST0_LIMIT="`$LFS quota -o $OST0_UUID -u $TSTUSR $MOUNT | awk '/^.*[[:digit:]+][[:space:]+]/ { print $3 }'`"
+ [ $OST0_LIMIT -eq $BUNIT_SZ ] || error "high limits not released!"
+ echo " limits on $OST0_UUID = $OST0_LIMIT"
+
+ # cleanup
+ $LFS setquota -u $TSTUSR 0 0 0 0 $MOUNT
+}
+run_test 7 "Quota recovery (only block limit) ======"
+
+# run dbench with quota enabled
+test_8() {
+ BLK_LIMIT=$((100 * 1024 * 1024)) # 100G
+ FILE_LIMIT=1000000
+
+ echo " Set enough high limit for user: $TSTUSR"
+ $LFS setquota -u $TSTUSR 0 $BLK_LIMIT 0 $FILE_LIMIT $MOUNT
+ echo " Set enough high limit for group: $TSTUSR"
+ $LFS setquota -g $USER 0 $BLK_LIMIT 0 $FILE_LIMIT $MOUNT
+
+ TGT=$TSTDIR/client.txt
+ SRC=${SRC:-/usr/lib/dbench/client.txt}
+ [ ! -e $TGT -a -e $SRC ] && echo " copying $SRC to $TGT" && cp $SRC $TGT
+ SRC=/usr/lib/dbench/client_plain.txt
+ [ ! -e $TGT -a -e $SRC ] && echo " copying $SRC to $TGT" && cp $SRC $TGT
+
+ SAVE_PWD=$PWD
+ cd $TSTDIR
+ $RUNAS dbench -c client.txt 3
+ RC=$?
+
+ cd $SAVE_PWD
+ return $RC
+}
+run_test 8 "Run dbench with quota enabled ==========="
+
+# turn off quota
+test_9()
+{
+ $LFS quotaoff $MOUNT
+ return 0
+}
+run_test 9 "Quota off ==============================="
+
+
+log "cleanup: ======================================================"
+if [ "`mount | grep ^$NAME`" ]; then
+ rm -fr $TSTDIR
+ post_test
+ # delete test user and group
+ userdel "$TSTUSR"
+ if [ "$I_MOUNTED" = "yes" ]; then
+ sh llmountcleanup.sh || error "llmountcleanup failed"
+ fi
+fi
+
+echo '=========================== finished ==============================='
+[ -f "$SANITYLOG" ] && cat $SANITYLOG && exit 1 || true
+
self.nspath = self.db.get_val('nspath', '')
self.mkfsoptions = '-i 4096 ' + self.db.get_val('mkfsoptions', '')
self.mountfsoptions = self.db.get_val('mountfsoptions', '')
+ self.quota = self.db.get_val('quota', '')
# overwrite the orignal MDSDEV name and uuid with the MDS name and uuid
target_uuid = self.db.get_first_ref('target')
mds = self.db.lookup(target_uuid)
self.uuid = target_uuid
# loading modules
+ if self.quota:
+ self.add_lustre_module('quota', 'lquota')
self.add_lustre_module('mdc', 'mdc')
self.add_lustre_module('osc', 'osc')
self.add_lustre_module('lov', 'lov')
print 'MDS mount options: ' + mountfsoptions
lctl.newdev("mds", self.name, self.uuid,
- setup ="%s %s %s %s" %(blkdev, self.fstype, self.name, mountfsoptions))
+ setup ="%s %s %s %s %s" %(blkdev, self.fstype, self.name,
+ mountfsoptions, self.quota))
self.group_upcall = self.db.get_val('group_upcall','')
sys_set_group_upcall(self.name, self.group_upcall)
if self.size > 1000000:
self.mkfsoptions = '-i 16384 ' + self.mkfsoptions
self.mountfsoptions = self.db.get_val('mountfsoptions', '')
+ self.quota = self.db.get_val('quota', '')
self.fstype = self.db.get_val('fstype', '')
if sys_get_branch() == '2.4' and self.fstype == 'ldiskfs':
self.target_dev_uuid = self.uuid
self.uuid = target_uuid
# modules
+ if self.quota:
+ self.add_lustre_module('quota', 'lquota')
self.add_lustre_module('ost', 'ost')
# FIXME: should we default to ext3 here?
if self.fstype == 'ldiskfs':
print 'OST mount options: ' + mountfsoptions
lctl.newdev(self.osdtype, self.name, self.uuid,
- setup ="%s %s %s %s" %(blkdev, self.fstype,
- self.failover_ost, mountfsoptions))
+ setup ="%s %s %s %s %s" %(blkdev, self.fstype,
+ self.failover_ost, mountfsoptions,
+ self.quota))
if not is_prepared('OSS'):
lctl.newdev("ost", 'OSS', 'OSS_UUID', setup ="")
self.vosc = VOSC(obd, client_uuid, self.name)
self.mdc = get_mdc(db, client_uuid, self.name, self.mds_uuid)
+ mds_db = self.db.lookup(self.mds_uuid)
+ quota = mds_db.get_val('quota', '')
+ if quota:
+ self.add_lustre_module('quota', 'lquota')
self.add_lustre_module('mdc', 'mdc')
self.add_lustre_module('llite', 'llite')
#include <errno.h>
#include <pwd.h>
#include <grp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
#include <lnet/api-support.h>
#include <lnet/lnetctl.h>
unsigned int libcfs_subsystem_debug = 0;
-#ifdef HAVE_QUOTA_SUPPORT
-
-/* FIXME: Q_SYNC ... commands defined in linux/quota.h seems broken,
- * so define new commands with the value in kernel */
-#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 */
-
-/* Where is this stupid thing supposed to be defined? */
-#ifndef USRQUOTA
-# define USRQUOTA 0
-# define GRPQUOTA 1
-#endif
-
-#endif /* HAVE_QUOTA_SUPPORT */
-
/* all functions */
static int lfs_setstripe(int argc, char **argv);
static int lfs_find(int argc, char **argv);
static int lfs_check(int argc, char **argv);
static int lfs_catinfo(int argc, char **argv);
#ifdef HAVE_QUOTA_SUPPORT
-static int lfs_quotachog(int argc, char **argv);
+static int lfs_quotachown(int argc, char **argv);
static int lfs_quotacheck(int argc, char **argv);
static int lfs_quotaon(int argc, char **argv);
static int lfs_quotaoff(int argc, char **argv);
"\tnode name must be provided when use keyword config."},
{"osts", lfs_osts, 0, "osts"},
#ifdef HAVE_QUOTA_SUPPORT
- {"quotachog",lfs_quotachog, 0,
- "Change all files owner or group in specified filesystem.\n"
- "usage: quotachog [-i] <filesystem>\n"
+ {"quotachown",lfs_quotachown, 0,
+ "Change files' owner or group on the specified filesystem.\n"
+ "usage: quotachown [-i] <filesystem>\n"
"\t-i: ignore error if file is not exist\n"},
{"quotacheck", lfs_quotacheck, 0,
"Scan the specified filesystem for disk usage, and create,\n"
"usage: setquota [ -u | -g ] <name> <block-softlimit> <block-hardlimit> <inode-softlimit> <inode-hardlimit> <filesystem>\n"
" setquota -t [ -u | -g ] <block-grace> <inode-grace> <filesystem>"},
{"quota", lfs_quota, 0, "Display disk usage and limits.\n"
- "usage: quota -t [ -u |-g ] <filesystem>\n"
- " quota [ -o obd_uuid ] [ -u | -g ] [name] <filesystem>"},
+ "usage: quota [ -o obd_uuid ] [ -u | -g ] [name] <filesystem>"},
#endif
{"help", Parser_help, 0, "help"},
{"exit", Parser_quit, 0, "quit"},
}
#ifdef HAVE_QUOTA_SUPPORT
-static int lfs_quotachog(int argc, char **argv)
+static int lfs_quotachown(int argc, char **argv)
{
int c,rc;
flag++;
break;
default:
- fprintf(stderr, "error: %s: option '-%c' unrecognized\n", argv[0], c);
+ fprintf(stderr, "error: %s: option '-%c' "
+ "unrecognized\n", argv[0], c);
return CMD_HELP;
}
}
if (optind == argc)
return CMD_HELP;
- rc = llapi_quotachog(argv[optind], flag);
+ rc = llapi_quotachown(argv[optind], flag);
if(rc)
fprintf(stderr,"error: change file owner/group failed.\n");
return rc;
check_type |= 0x02;
break;
default:
- fprintf(stderr, "error: %s: option '-%c' unrecognized\n", argv[0], c);
+ fprintf(stderr, "error: %s: option '-%c' "
+ "unrecognized\n", argv[0], c);
return CMD_HELP;
}
}
qctl.qc_cmd = LUSTRE_Q_QUOTAOFF;
break;
default:
- fprintf(stderr, "error: %s: option '-%c' unrecognized\n", argv[0], c);
+ fprintf(stderr, "error: %s: option '-%c' "
+ "unrecognized\n", argv[0], c);
return CMD_HELP;
}
}
qctl.qc_type |= 0x02;
break;
default:
- fprintf(stderr, "error: %s: option '-%c' unrecognized\n", argv[0], c);
+ fprintf(stderr, "error: %s: option '-%c' "
+ "unrecognized\n", argv[0], c);
return CMD_HELP;
}
}
qctl.qc_cmd = LUSTRE_Q_SETINFO;
break;
default:
- fprintf(stderr, "error: %s: option '-%c' unrecognized\n", argv[0], c);
+ fprintf(stderr, "error: %s: option '-%c' "
+ "unrecognized\n", argv[0], c);
return CMD_HELP;
}
}
qctl.qc_type--;
if (qctl.qc_type == UGQUOTA) {
- fprintf(stderr, "error: user and group quotas can't be set together\n");
+ fprintf(stderr, "error: user and group quotas can't be set "
+ "both\n");
return CMD_HELP;
}
if (qctl.qc_cmd == LUSTRE_Q_SETQUOTA) {
- struct if_dqblk *dqb = &qctl.qc_dqblk;
+ struct obd_dqblk *dqb = &qctl.qc_dqblk;
if (optind + 6 != argc)
return CMD_HELP;
ARG2INT(dqb->dqb_bhardlimit, argv[optind++], "block-hardlimit");
ARG2INT(dqb->dqb_isoftlimit, argv[optind++], "inode-softlimit");
ARG2INT(dqb->dqb_ihardlimit, argv[optind++], "inode-hardlimit");
+
+ dqb->dqb_valid = QIF_LIMITS;
} else {
- struct if_dqinfo *dqi = &qctl.qc_dqinfo;
+ struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
if (optind + 3 != argc)
return CMD_HELP;
grace2str(seconds - now, buf);
}
+static void print_quota_title(char *name, struct if_quotactl *qctl)
+{
+ printf("Disk quotas for %s %s (%cid %u):\n",
+ type2name(qctl->qc_type), name,
+ *type2name(qctl->qc_type), qctl->qc_id);
+ printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
+ "Filesystem",
+ "blocks", "quota", "limit", "grace",
+ "files", "quota", "limit", "grace");
+}
-static void print_quota(char *mnt, char *name, struct if_quotactl *qctl)
+static void print_quota(char *mnt, struct if_quotactl *qctl, int ost_only)
{
time_t now;
if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
int bover = 0, iover = 0;
- struct if_dqblk *dqb = &qctl->qc_dqblk;
+ struct obd_dqblk *dqb = &qctl->qc_dqblk;
if (dqb->dqb_bhardlimit &&
toqb(dqb->dqb_curspace) > dqb->dqb_bhardlimit) {
}
}
- printf("Disk quotas for %s %s (%cid %u):\n",
- type2name(qctl->qc_type), name,
- *type2name(qctl->qc_type), qctl->qc_id);
- printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
- "Filesystem",
- "blocks", "quota", "limit", "grace",
- "files", "quota", "limit", "grace");
-
#if 0 /* XXX: always print quotas even when no usages */
if (dqb->dqb_curspace || dqb->dqb_curinodes)
#endif
printf("%s\n%15s", mnt, "");
else
printf("%15s", mnt);
+
if (bover)
diff2str(dqb->dqb_btime, timebuf, now);
- sprintf(numbuf[0], LPU64, toqb(dqb->dqb_curspace));
- sprintf(numbuf[1], LPU64, dqb->dqb_bsoftlimit);
- sprintf(numbuf[2], LPU64, dqb->dqb_bhardlimit);
- printf(" %7s%c %6s %7s %7s", numbuf[0], bover ? '*' : ' ', numbuf[1],
+
+ sprintf(numbuf[0], "%llu", toqb(dqb->dqb_curspace));
+ sprintf(numbuf[1], "%llu", dqb->dqb_bsoftlimit);
+ sprintf(numbuf[2], "%llu", dqb->dqb_bhardlimit);
+ printf(" %7s%c %6s %7s %7s",
+ numbuf[0], bover ? '*' : ' ', numbuf[1],
numbuf[2], bover > 1 ? timebuf : "");
+
if (iover)
diff2str(dqb->dqb_itime, timebuf, now);
- sprintf(numbuf[0], LPU64, dqb->dqb_curinodes);
- sprintf(numbuf[1], LPU64, dqb->dqb_isoftlimit);
- sprintf(numbuf[2], LPU64, dqb->dqb_ihardlimit);
- printf(" %7s%c %6s %7s %7s\n", numbuf[0], iover ? '*' : ' ', numbuf[1],
- numbuf[2], iover > 1 ? timebuf : "");
+
+ sprintf(numbuf[0], "%llu", dqb->dqb_curinodes);
+ sprintf(numbuf[1], "%llu", dqb->dqb_isoftlimit);
+ sprintf(numbuf[2], "%llu", dqb->dqb_ihardlimit);
+ if (!ost_only)
+ printf(" %7s%c %6s %7s %7s",
+ numbuf[0], iover ? '*' : ' ', numbuf[1],
+ numbuf[2], iover > 1 ? timebuf : "");
+ printf("\n");
}
- } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO || qctl->qc_cmd == Q_GETOINFO) {
+ } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
+ qctl->qc_cmd == Q_GETOINFO) {
char bgtimebuf[40];
char igtimebuf[40];
grace2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf);
grace2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf);
- printf("Block grace time: %s; Inode grace time: %s\n", bgtimebuf, igtimebuf);
+ printf("Block grace time: %s; Inode grace time: %s\n",
+ bgtimebuf, igtimebuf);
+ }
+}
+
+static void print_mds_quota(char *mnt, struct if_quotactl *qctl)
+{
+ int rc;
+
+ /* XXX: this is a flag to mark that only mds quota is wanted */
+ qctl->qc_dqblk.dqb_valid = 1;
+ rc = llapi_quotactl(mnt, qctl);
+ if (rc) {
+ fprintf(stderr, "quotactl failed: %s\n", strerror(errno));
+ return;
+ }
+ qctl->qc_dqblk.dqb_valid = 0;
+
+ print_quota(qctl->obd_uuid.uuid, qctl, 0);
+}
+
+static void print_lov_quota(char *mnt, struct if_quotactl *qctl)
+{
+ DIR *dir;
+ struct obd_uuid uuids[1024], *uuidp;
+ int obdcount = 1024;
+ int i, rc;
+
+ dir = opendir(mnt);
+ if (!dir) {
+ fprintf(stderr, "open %s failed: %s\n", mnt, strerror(errno));
+ return;
+ }
+
+ rc = llapi_lov_get_uuids(dirfd(dir), uuids, &obdcount);
+ if (rc != 0) {
+ fprintf(stderr, "get ost uuid failed: %s\n", strerror(errno));
+ goto out;
+ }
+
+ for (i = 0, uuidp = uuids; i < obdcount; i++, uuidp++) {
+ memcpy(&qctl->obd_uuid, uuidp, sizeof(*uuidp));
+
+ rc = llapi_quotactl(mnt, qctl);
+ if (rc) {
+ fprintf(stderr, "%s quotactl failed: %s\n",
+ uuidp->uuid, strerror(errno));
+ continue;
+ }
+
+ print_quota(uuidp->uuid, qctl, 1);
}
+
+out:
+ closedir(dir);
+ return;
}
static int lfs_quota(int argc, char **argv)
strncpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
break;
default:
- fprintf(stderr, "error: %s: option '-%c' unrecognized\n", argv[0], c);
+ fprintf(stderr, "error: %s: option '-%c' "
+ "unrecognized\n", argv[0], c);
return CMD_HELP;
}
}
qctl.qc_type--;
if (qctl.qc_type == UGQUOTA) {
- fprintf(stderr, "error: user or group can't be specified together\n");
+ fprintf(stderr, "error: user or group can't be specified"
+ "both\n");
return CMD_HELP;
}
- if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && optind + 2 == argc) {
+ if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
+ if (optind + 2 != argc)
+ return CMD_HELP;
+
name = argv[optind++];
rc = name2id(&qctl.qc_id, name, qctl.qc_type);
if (rc) {
name, strerror(errno));
return CMD_HELP;
}
+ print_quota_title(name, &qctl);
} else if (optind + 1 != argc) {
return CMD_HELP;
}
if (!name)
rc = id2name(&name, getuid(), qctl.qc_type);
- print_quota(mnt, name, &qctl);
+ if (*obd_uuid) {
+ mnt = "";
+ name = obd_uuid;
+ }
+
+ print_quota(mnt, &qctl, 0);
+
+ if (!*obd_uuid) {
+ print_mds_quota(mnt, &qctl);
+ print_lov_quota(mnt, &qctl);
+ }
+
return 0;
}
#endif /* HAVE_QUOTA_SUPPORT */
#include <linux/lustre_lib.h>
#include <lustre/liblustreapi.h>
#include <linux/obd_lov.h>
+#include <lustre/liblustreapi.h>
static void err_msg(char *fmt, ...)
{
return rc;
}
-int llapi_target_check(int type_num, char **obd_type, char *dir)
+int llapi_target_iterate(int type_num, char **obd_type, void *args, llapi_cb_t cb)
{
char buf[MAX_STRING_SIZE];
FILE *fp = fopen(DEVICES_LIST, "r");
while (fgets(buf, sizeof(buf), fp) != NULL) {
char *obd_type_name = NULL;
char *obd_name = NULL;
+ char *obd_uuid = NULL;
char rawbuf[OBD_MAX_IOCTL_BUFFER];
char *bufl = rawbuf;
char *bufp = buf;
obd_type_name = strsep(&bufp, " ");
}
obd_name = strsep(&bufp, " ");
+ obd_uuid = strsep(&bufp, " ");
memset(&osfs_buffer, 0, sizeof (osfs_buffer));
if (strcmp(obd_type_name, obd_type[i]) != 0)
continue;
- rc = llapi_ping(obd_type_name, obd_name);
- if (rc) {
- fprintf(stderr, "error: check %s: %s\n",
- obd_name, strerror(rc = errno));
- } else {
- printf("%s active.\n", obd_name);
- }
+ cb(obd_type_name, obd_name, obd_uuid, args);
}
}
fclose(fp);
return rc;
}
+static void do_target_check(char *obd_type_name, char *obd_name,
+ char *obd_uuid, void *args)
+{
+ int rc;
+
+ rc = llapi_ping(obd_type_name, obd_name);
+ if (rc) {
+ fprintf(stderr, "error: check %s: %s\n",
+ obd_name, strerror(rc = errno));
+ } else {
+ printf("%s active.\n", obd_name);
+ }
+}
+
+int llapi_target_check(int type_num, char **obd_type, char *dir)
+{
+ return llapi_target_iterate(type_num, obd_type, NULL, do_target_check);
+}
+
#undef MAX_STRING_SIZE
int llapi_catinfo(char *dir, char *keyword, char *node_name)
while (1) {
rc = ioctl(dirfd(root), LL_IOC_POLL_QUOTACHECK, qchk);
- if (!rc || errno != ENODATA)
+ if (!rc)
break;
sleep(poll_intvl);
if (poll_intvl < 30)
return rc;
}
-static int quotachog_process_file(DIR *dir, char *dname, char *fname,
+static int quotachown_process_file(DIR *dir, char *dname, char *fname,
struct find_param *param)
{
lstat_t *st;
st = ¶m->lmd->lmd_st;
snprintf(pathname, sizeof(pathname), "%s/%s", dname, fname);
+
+ /* libc chown() will do extra check, and if the real owner is
+ * the same as the ones to set, it won't fall into kernel, so
+ * invoke syscall directly. */
rc = syscall(SYS_chown, pathname, st->st_uid, st->st_gid);
if (rc)
fprintf(stderr, "chown %s (%u,%u) fail: %s\n",
return rc;
}
-int llapi_quotachog(char *path, int flag)
+int llapi_quotachown(char *path, int flag)
{
struct find_param param;
int ret = 0;
param.recursive = 1;
param.verbose = 0;
param.quiet = 1;
- param.process_file = quotachog_process_file;
+ param.process_file = quotachown_process_file;
ret = prepare_find(¶m);
if (ret)
--mdsuuid uuid
--mkfsoptions options
--mountfsoptions options
+ --quota quotaon=u|g|ug,iunit=,bunit=,itune=,btune=
--add lov
--lov lov_name
--ostuuid uuid
--mkfsoptions options
--mountfsoptions options
+ --quota quotaon=u|g|ug,iunit=,bunit=,itune=,btune=
--add mtpt - Mountpoint
--node node_name
('mdsuuid', "Optional argument to specify MDS UUID", PARAM,""),
('nspath', "Local mount point of server namespace.", PARAM,""),
('format', ""),
-
+ ('quota', "quotaon:enable quota, only u|g|ug is supported now. \
+ iunit: the unit for slave to acquire/release inode quota from/to masteri.\
+ Int type (>0), default value in Lustre is 5000 inodes.\
+ bunit: the unit for slave to acquire/release block quota from/to master.\
+ Mbytes (>0), default value in Lustre is 100(Mbytes).\
+ itune: used to tune the threthold. When inode quota usage reach the threthold,\
+ slave should acquire/release inode quota from/to master.\
+ Int type (100 > btune > 0), default value in Lustre is 50 (percentge).\
+ inode threthold = iunit * itune / 100.\
+ btune: used to tune the threthold. When block quota usage reach the threthold,\
+ slave should acquire/release block quota from/to master.\
+ Int type (100 > btune > 0), default value in Lustre is 50 (percentage).\
+ block threthold = bunit * btune / 100.", PARAM,""),
# clients: mountpoint and echo
('echo_client', "", PARAM),
('path', "Specify the mountpoint for Lustre.", PARAM),
def osd(self, name, uuid, fstype, osdtype, devname, format, ost_uuid,
node_uuid, dev_size=0, journal_size=0, inode_size=0, nspath="",
- mkfsoptions="", mountfsoptions=""):
+ mkfsoptions="", mountfsoptions="", quota=""):
osd = self.newService("osd", name, uuid)
osd.setAttribute('osdtype', osdtype)
osd.appendChild(self.ref("target", ost_uuid))
self.addElement(osd, "mkfsoptions", mkfsoptions)
if mountfsoptions:
self.addElement(osd, "mountfsoptions", mountfsoptions)
+ if quota:
+ self.addElement(osd, "quota", quota)
if nspath:
self.addElement(osd, "nspath", nspath)
return osd
def mdsdev(self, name, uuid, fstype, devname, format, node_uuid,
mds_uuid, dev_size=0, journal_size=0, inode_size=256,
- nspath="", mkfsoptions="", mountfsoptions="", group_upcall=""):
+ nspath="", mkfsoptions="", mountfsoptions="", quota="", group_upcall=""):
mdd = self.newService("mdsdev", name, uuid)
self.addElement(mdd, "fstype", fstype)
dev = self.addElement(mdd, "devpath", devname)
self.addElement(mdd, "mkfsoptions", mkfsoptions)
if mountfsoptions:
self.addElement(mdd, "mountfsoptions", mountfsoptions)
+ if quota:
+ self.addElement(mdd, "quota", quota)
if group_upcall:
self.addElement(mdd, "group_upcall", group_upcall)
nspath = get_option(options, 'nspath')
mkfsoptions = get_option(options, 'mkfsoptions')
mountfsoptions = get_option(options, 'mountfsoptions')
+ quota = get_option(options, 'quota')
group_upcall = get_option(options, 'group_upcall')
node_uuid = name2uuid(lustre, node_name, 'node')
mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
get_format_flag(options), node_uuid, mds_uuid,
size, journal_size, inode_size, nspath, mkfsoptions,
- mountfsoptions, group_upcall)
+ mountfsoptions, quota, group_upcall)
lustre.appendChild(mdd)
journal_size = ''
inode_size = ''
mkfsoptions = ''
- mountfsoptions = ''
+ mountfsoptions = ''
+ quota = ''
else:
devname = get_option(options, 'dev') # can be unset for bluearcs
size = get_option(options, 'size')
journal_size = get_option(options, 'journal_size')
inode_size = get_option(options, 'inode_size')
mkfsoptions = get_option(options, 'mkfsoptions')
- mountfsoptions = get_option(options, 'mountfsoptions')
+ mountfsoptions = get_option(options, 'mountfsoptions')
+ quota = get_option(options, 'quota')
nspath = get_option(options, 'nspath')
osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
get_format_flag(options), ost_uuid, node_uuid, size,
journal_size, inode_size, nspath, mkfsoptions,
- mountfsoptions)
+ mountfsoptions, quota)
node = findByName(lustre, node_name, "node")
lustre_cfg_bufs_reset(&bufs, lcfg_devname);
- if (argc > 5)
+ if (argc > 6)
return CMD_HELP;
for (i = 1; i < argc; i++) {