From: niu Date: Fri, 4 Nov 2005 05:46:41 +0000 (+0000) Subject: land b1_4_quota (20051104_1137) X-Git-Tag: v1_7_100~1^103~4^2~246 X-Git-Url: https://git.whamcloud.com/?a=commitdiff_plain;h=93b639809cc7150dd8bf3f4eecd9c46a924575d3;p=fs%2Flustre-release.git land b1_4_quota (20051104_1137) --- diff --git a/ldiskfs/ldiskfs/Makefile.in b/ldiskfs/ldiskfs/Makefile.in index 2f0cdc7..92d9b6b 100644 --- a/ldiskfs/ldiskfs/Makefile.in +++ b/ldiskfs/ldiskfs/Makefile.in @@ -1,6 +1,8 @@ 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) @@ -11,13 +13,16 @@ linux_headers := $(wildcard @LINUX@/include/linux/ext3*.h) 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 diff --git a/lustre/Makefile.in b/lustre/Makefile.in index d6e7684..6da79a1 100644 --- a/lustre/Makefile.in +++ b/lustre/Makefile.in @@ -9,5 +9,6 @@ subdir-m += obdecho @SERVER_TRUE@subdir-m += mds obdfilter ost @CLIENT_TRUE@subdir-m += mdc llite +@QUOTA_TRUE@subdir-m += quota @INCLUDE_RULES@ diff --git a/lustre/autoMakefile.am b/lustre/autoMakefile.am index 92426b5..1e38c7a 100644 --- a/lustre/autoMakefile.am +++ b/lustre/autoMakefile.am @@ -12,6 +12,8 @@ SERVER_SUBDIRS := ldiskfs obdfilter ost mds CLIENT_SUBDIRS := mdc llite +QUOTA_SUBDIRS := quota + LIBLUSTRE_SUBDIRS := liblustre SUBDIRS := $(ALWAYS_SUBDIRS) @@ -24,6 +26,10 @@ if CLIENT SUBDIRS += $(CLIENT_SUBDIRS) endif +if QUOTA +SUBDIRS += $(QUOTA_SUBDIRS) +endif + # this needs to be after the client subdirs if LIBLUSTRE if !CLIENT @@ -33,7 +39,7 @@ SUBDIRS += $(LIBLUSTRE_SUBDIRS) endif DIST_SUBDIRS := $(ALWAYS_SUBDIRS) $(SERVER_SUBDIRS) $(CLIENT_SUBDIRS) \ - $(LIBLUSTRE_SUBDIRS) + $(LIBLUSTRE_SUBDIRS) $(QUOTA_SUBDIRS) EXTRA_DIST = BUGS FDL kernel_patches diff --git a/lustre/autoconf/lustre-core.m4 b/lustre/autoconf/lustre-core.m4 index 5b48d1c..e6cdb7b 100644 --- a/lustre/autoconf/lustre-core.m4 +++ b/lustre/autoconf/lustre-core.m4 @@ -439,6 +439,7 @@ AC_DEFUN([LC_PROG_LINUX], LC_CONFIG_BACKINGFS fi LC_CONFIG_PINGER +LC_CONFIG_QUOTA LC_STRUCT_KIOBUF LC_FUNC_COND_RESCHED @@ -512,6 +513,23 @@ ac_configure_args="$ac_configure_args --with-lustre-hack --with-sockets" ]) # +# 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 @@ -526,16 +544,6 @@ AC_CHECK_HEADERS([asm/page.h sys/user.h stdint.h]) # 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 -]) - -AC_CHECK_TYPES([struct if_dqblk],[],[],[ -#define __ASM_X86_64_PROCESSOR_H -#include -]) - # liblustre/llite_lib.h AC_CHECK_HEADERS([xtio.h file.h]) @@ -573,6 +581,7 @@ AM_CONDITIONAL(LIBLUSTRE_TESTS, test x$enable_liblustre_tests = xyes) AM_CONDITIONAL(MPITESTS, test x$enable_mpitests = xyes, Build MPI Tests) AM_CONDITIONAL(CLIENT, test x$enable_client = xyes) AM_CONDITIONAL(SERVER, test x$enable_server = xyes) +AM_CONDITIONAL(QUOTA, test x$enable_quota = xyes) ]) # @@ -625,6 +634,8 @@ lustre/ost/Makefile 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 diff --git a/lustre/doc/lfs.1 b/lustre/doc/lfs.1 index 4d63cad..b31f5ff 100644 --- a/lustre/doc/lfs.1 +++ b/lustre/doc/lfs.1 @@ -11,6 +11,20 @@ lfs \- Lustre utility to create a file with specific striping pattern, find the .br .B lfs setstripe .br +.B lfs quotachown [-i] +.br +.B lfs quotacheck [-ug] +.br +.B lfs quotaon [-ugf] +.br +.B lfs quotaoff [-ug] +.br +.B lfs setquota [-u|-g] +.br +.B lfs quota [-o obd_uuid] [-u|-g] +.br +.B lfs setstripe +.br .B lfs check .SH DESCRIPTION .B lfs @@ -29,6 +43,24 @@ To list the extended attributes for a given filename or files in a directory or .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 @@ -57,6 +89,26 @@ Recursively list the extended attributes of all files in a given directory tree .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 diff --git a/lustre/doc/lfs.lyx b/lustre/doc/lfs.lyx index 091c043..8e08a86 100644 --- a/lustre/doc/lfs.lyx +++ b/lustre/doc/lfs.lyx @@ -32,7 +32,8 @@ LFS 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 @@ -70,6 +71,43 @@ setstripe -d \series bold lfs\SpecialChar ~ check +\layout Standard + + +\series bold +lfs\SpecialChar ~ +quotachog [-i] +\layout Standard + + +\series bold +lfs\SpecialChar ~ +quotacheck [-ug] +\layout Standard + + +\series bold +lfs\SpecialChar ~ +quotaon [-ugf] +\layout Standard + + +\series bold +lfs\SpecialChar ~ +quotaoff [-ug] +\layout Standard + + +\series bold +lfs\SpecialChar ~ +setquota [-u|-g] + +\layout Standard + + +\series bold +lfs\SpecialChar ~ +quota [-o obd_uuid] [-u|-g] \layout Subsection DESCRIPTION @@ -77,7 +115,8 @@ 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 @@ -129,6 +168,55 @@ osts \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 @@ -239,6 +327,77 @@ List all the OSTs \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 diff --git a/lustre/include/linux/lustre_compat25.h b/lustre/include/linux/lustre_compat25.h index e5260f1..6169d34 100644 --- a/lustre/include/linux/lustre_compat25.h +++ b/lustre/include/linux/lustre_compat25.h @@ -172,8 +172,10 @@ static inline int cleanup_group_info(void) #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) diff --git a/lustre/include/linux/lustre_fsfilt.h b/lustre/include/linux/lustre_fsfilt.h index a446c65..ebb798b 100644 --- a/lustre/include/linux/lustre_fsfilt.h +++ b/lustre/include/linux/lustre_fsfilt.h @@ -94,7 +94,7 @@ struct fsfilt_operations { 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); }; @@ -327,10 +327,10 @@ static inline int fsfilt_quotactl(struct obd_device *obd, 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; } diff --git a/lustre/include/linux/lustre_idl.h b/lustre/include/linux/lustre_idl.h index f7807c2..b7fc6aa 100644 --- a/lustre/include/linux/lustre_idl.h +++ b/lustre/include/linux/lustre_idl.h @@ -620,28 +620,6 @@ struct mds_body { 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 */ @@ -1201,10 +1179,10 @@ extern void lustre_swab_lustre_cfg(struct lustre_cfg *lcfg); /* 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); diff --git a/lustre/include/linux/lustre_log.h b/lustre/include/linux/lustre_log.h index 4cb00a5..d53a259 100644 --- a/lustre/include/linux/lustre_log.h +++ b/lustre/include/linux/lustre_log.h @@ -68,11 +68,6 @@ struct llog_handle { } 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); @@ -112,7 +107,7 @@ int llog_cleanup(struct llog_ctxt *); 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); @@ -122,8 +117,7 @@ int llog_obd_origin_setup(struct obd_device *obd, int index, 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, @@ -173,8 +167,7 @@ struct llog_operations { 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, diff --git a/lustre/include/linux/lustre_quota.h b/lustre/include/linux/lustre_quota.h index a28c618..3c5f5473 100644 --- a/lustre/include/linux/lustre_quota.h +++ b/lustre/include/linux/lustre_quota.h @@ -5,23 +5,91 @@ #define _LUSTRE_QUOTA_H #ifdef __KERNEL__ -# include +#include +#include +#include +#include #endif #include +#include +#include + +struct obd_device; +struct client_obd; + +#ifndef NR_DQHASH +#define NR_DQHASH 45 +#endif #ifdef HAVE_QUOTA_SUPPORT -#include -#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) @@ -38,7 +106,6 @@ static inline int lustre_write_quota_info(struct lustre_quota_info *lqi, { return 0; } -#ifdef __KERNEL__ static inline int lustre_read_dquot(struct lustre_dquot *dquot) { return 0; @@ -47,51 +114,283 @@ static inline int lustre_commit_dquot(struct lustre_dquot *dquot) { 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 */ diff --git a/lustre/include/linux/obd.h b/lustre/include/linux/obd.h index 86c150b..7daf6f5 100644 --- a/lustre/include/linux/obd.h +++ b/lustre/include/linux/obd.h @@ -180,6 +180,13 @@ struct obd_histogram { 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 @@ -189,8 +196,9 @@ struct filter_ext { }; 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; @@ -284,11 +292,6 @@ struct mds_server_data; #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; @@ -343,16 +346,18 @@ struct client_obd { 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; @@ -382,9 +387,9 @@ struct mds_obd { 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, @@ -594,6 +599,7 @@ struct obd_device { time_t obd_recovery_end; union { + struct obd_device_target obt; struct filter_obd filter; struct mds_obd mds; struct client_obd cli; @@ -797,4 +803,15 @@ static inline void obd_transno_commit_cb(struct obd_device *obd, __u64 transno, } } +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 */ diff --git a/lustre/include/linux/obd_class.h b/lustre/include/linux/obd_class.h index b89063c..38d7da4 100644 --- a/lustre/include/linux/obd_class.h +++ b/lustre/include/linux/obd_class.h @@ -1102,11 +1102,6 @@ static inline struct obdo *obdo_alloc(void) 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)); diff --git a/lustre/include/linux/obd_ost.h b/lustre/include/linux/obd_ost.h index 32b9852..0b15af6 100644 --- a/lustre/include/linux/obd_ost.h +++ b/lustre/include/linux/obd_ost.h @@ -13,6 +13,7 @@ #include +#define LUSTRE_FILTER_NAME "obdfilter" #define LUSTRE_OST_NAME "ost" #define LUSTRE_OSC_NAME "osc" #define LUSTRE_SANOSC_NAME "sanosc" diff --git a/lustre/include/linux/obd_support.h b/lustre/include/linux/obd_support.h index 812143d..2ab3d1f 100644 --- a/lustre/include/linux/obd_support.h +++ b/lustre/include/linux/obd_support.h @@ -163,6 +163,7 @@ extern wait_queue_head_t obd_race_waitq; #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 diff --git a/lustre/include/lustre/liblustreapi.h b/lustre/include/lustre/liblustreapi.h index 6527f40..35da48d 100644 --- a/lustre/include/lustre/liblustreapi.h +++ b/lustre/include/lustre/liblustreapi.h @@ -8,6 +8,8 @@ #include +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); @@ -19,8 +21,9 @@ extern int llapi_target_check(int num_types, char **obd_types, char *dir); 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 diff --git a/lustre/include/lustre/lustre_user.h b/lustre/include/lustre/lustre_user.h index 8aa9939..4d85bfb 100644 --- a/lustre/include/lustre/lustre_user.h +++ b/lustre/include/lustre/lustre_user.h @@ -139,14 +139,20 @@ static inline void obd_str2uuid(struct obd_uuid *uuid, char *tmp) 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 @@ -170,8 +176,6 @@ struct mds_grp_downcall_data { # endif #endif -#ifdef HAVE_QUOTA_SUPPORT - #ifdef NEED_QUOTA_DEFS #ifndef QUOTABLOCK_BITS #define QUOTABLOCK_BITS 10 @@ -185,18 +189,31 @@ struct mds_grp_downcall_data { #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; @@ -206,42 +223,20 @@ struct if_dqblk { __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__) diff --git a/lustre/kernel_patches/kernel_configs/uml-2.6.10-fc3.config b/lustre/kernel_patches/kernel_configs/uml-2.6.10-fc3.config index 30aab18..e7685c2 100644 --- a/lustre/kernel_patches/kernel_configs/uml-2.6.10-fc3.config +++ b/lustre/kernel_patches/kernel_configs/uml-2.6.10-fc3.config @@ -480,7 +480,9 @@ CONFIG_FS_POSIX_ACL=y # 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 diff --git a/lustre/kernel_patches/patches/kallsyms-2.4-bgl.patch b/lustre/kernel_patches/patches/kallsyms-2.4-bgl.patch index 6ec26cd..25f7954 100644 --- a/lustre/kernel_patches/patches/kallsyms-2.4-bgl.patch +++ b/lustre/kernel_patches/patches/kallsyms-2.4-bgl.patch @@ -252,7 +252,7 @@ Index: linux-bgl/kernel/kallsyms.c + 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 :- @@ -568,7 +568,7 @@ Index: linux-bgl/include/linux/kallsyms.h + 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 diff --git a/lustre/ldiskfs/Makefile.in b/lustre/ldiskfs/Makefile.in index 2f0cdc7..92d9b6b 100644 --- a/lustre/ldiskfs/Makefile.in +++ b/lustre/ldiskfs/Makefile.in @@ -1,6 +1,8 @@ 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) @@ -11,13 +13,16 @@ linux_headers := $(wildcard @LINUX@/include/linux/ext3*.h) 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 diff --git a/lustre/ldiskfs/lustre_quota_fmt.c b/lustre/ldiskfs/lustre_quota_fmt.c index cf2a23f..82bd9a6 100644 --- a/lustre/ldiskfs/lustre_quota_fmt.c +++ b/lustre/ldiskfs/lustre_quota_fmt.c @@ -7,7 +7,6 @@ * linux/fs/quota_v2.c */ - #ifndef EXPORT_SYMTAB # define EXPORT_SYMTAB #endif @@ -32,155 +31,166 @@ typedef char *dqbuf_t; #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<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<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) @@ -188,238 +198,258 @@ static void lustre_mark_info_dirty(struct lustre_mem_dqinfo *info) /* 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<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); } /* @@ -427,321 +457,508 @@ static inline int dq_insert_tree(struct lustre_dquot *dquot) */ 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); @@ -750,3 +967,4 @@ EXPORT_SYMBOL(lustre_write_quota_info); EXPORT_SYMBOL(lustre_read_dquot); EXPORT_SYMBOL(lustre_commit_dquot); EXPORT_SYMBOL(lustre_init_quota_info); +EXPORT_SYMBOL(lustre_get_qids); diff --git a/lustre/ldiskfs/lustre_quota_fmt.h b/lustre/ldiskfs/lustre_quota_fmt.h index 73d6120..28f5c15 100644 --- a/lustre/ldiskfs/lustre_quota_fmt.h +++ b/lustre/ldiskfs/lustre_quota_fmt.h @@ -1,4 +1,6 @@ -/* +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * * Lustre administrative quota format * * from @@ -30,15 +32,15 @@ * 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 */ }; /* @@ -46,18 +48,18 @@ struct lustre_disk_dqblk { */ /* 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 */ }; /* @@ -65,19 +67,18 @@ struct lustre_disk_dqinfo { * 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 */ diff --git a/lustre/ldiskfs/quotafmt_test.c b/lustre/ldiskfs/quotafmt_test.c index 53985d2..3b769b9 100644 --- a/lustre/ldiskfs/quotafmt_test.c +++ b/lustre/ldiskfs/quotafmt_test.c @@ -21,383 +21,415 @@ #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); } @@ -406,7 +438,7 @@ static int quotfmt_test_setup(struct obd_device *obd, obd_count len, void *buf) { struct lprocfs_static_vars lvars; struct lustre_cfg *lcfg = buf; - struct obd_device *tgt; + struct obd_device *tgt; int rc; ENTRY; @@ -433,24 +465,24 @@ static int quotfmt_test_setup(struct obd_device *obd, obd_count len, void *buf) } 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) diff --git a/lustre/ldlm/ldlm_lib.c b/lustre/ldlm/ldlm_lib.c index 5475efb..8c9d9cd 100644 --- a/lustre/ldlm/ldlm_lib.c +++ b/lustre/ldlm/ldlm_lib.c @@ -312,8 +312,7 @@ int client_obd_setup(struct obd_device *obddev, obd_count len, void *buf) } } - spin_lock_init(&cli->cl_qchk_lock); - cli->cl_qchk_stat = CL_NO_QUOTACHECK; + cli->cl_qchk_stat = CL_NOT_QUOTACHECKED; RETURN(rc); @@ -1013,7 +1012,7 @@ static void process_recovery_queue(struct obd_device *obd) 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); @@ -1340,3 +1339,64 @@ void target_committed_to_req(struct ptlrpc_request *req) } EXPORT_SYMBOL(target_committed_to_req); + +#ifdef HAVE_QUOTA_SUPPORT +int target_handle_qc_callback(struct ptlrpc_request *req) +{ + struct obd_quotactl *oqctl; + struct client_obd *cli = &req->rq_export->exp_obd->u.cli; + + oqctl = 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 */ diff --git a/lustre/liblustre/Makefile.am b/lustre/liblustre/Makefile.am index 9b4829a..72b71e6 100644 --- a/lustre/liblustre/Makefile.am +++ b/lustre/liblustre/Makefile.am @@ -18,6 +18,10 @@ LUSTRE_LIBS = libllite.a \ $(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 @@ -56,8 +60,8 @@ libllite_a_SOURCES = llite_lib.c super.c namei.c rw.c file.c dir.c \ 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 diff --git a/lustre/liblustre/genlib.sh b/lustre/liblustre/genlib.sh index b615afd..c7e7e06 100755 --- a/lustre/liblustre/genlib.sh +++ b/lustre/liblustre/genlib.sh @@ -21,6 +21,7 @@ SYSIO=$1 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" @@ -76,6 +77,10 @@ if $(echo "$LND_LIBS" | grep "ptllnd" >/dev/null) ; then 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 diff --git a/lustre/liblustre/lutil.c b/lustre/liblustre/lutil.c index a59ae84..bbb788b 100644 --- a/lustre/liblustre/lutil.c +++ b/lustre/liblustre/lutil.c @@ -62,6 +62,14 @@ void *inter_module_get(char *arg) return ldlm_namespace_cleanup; else if (!strcmp(arg, "ldlm_replay_locks")) return ldlm_replay_locks; +#ifdef HAVE_QUOTA_SUPPORT + else if (!strcmp(arg, "osc_quota_interface")) + return &osc_quota_interface; + else if (!strcmp(arg, "mdc_quota_interface")) + return &mdc_quota_interface; + else if (!strcmp(arg, "lov_quota_interface")) + return &lov_quota_interface; +#endif else return NULL; } diff --git a/lustre/llite/dir.c b/lustre/llite/dir.c index dd5c42d..48838dde 100644 --- a/lustre/llite/dir.c +++ b/lustre/llite/dir.c @@ -366,25 +366,14 @@ done: 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, @@ -671,114 +660,131 @@ 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; @@ -792,49 +798,35 @@ static int ll_dir_ioctl(struct inode *inode, struct file *file, 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: { diff --git a/lustre/llite/llite_internal.h b/lustre/llite/llite_internal.h index c969c0e..35fa8c7 100644 --- a/lustre/llite/llite_internal.h +++ b/lustre/llite/llite_internal.h @@ -271,7 +271,8 @@ struct ll_async_page { 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; diff --git a/lustre/llite/rw.c b/lustre/llite/rw.c index 6d5ea5f..fcbd874 100644 --- a/lustre/llite/rw.c +++ b/lustre/llite/rw.c @@ -370,6 +370,7 @@ static void ll_ap_fill_obdo(void *data, int cmd, struct obdo *oa) llap = LLAP_FROM_COOKIE(data); ll_inode_fill_obdo(llap->llap_page->mapping->host, cmd, oa); + EXIT; } @@ -601,7 +602,7 @@ static int queue_or_sync_write(struct obd_export *exp, struct inode *inode, 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 */ @@ -708,6 +709,8 @@ int ll_commit_write(struct file *file, struct page *page, unsigned from, 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)) { diff --git a/lustre/lov/lov_internal.h b/lustre/lov/lov_internal.h index 097e7c8..7bba3a0 100644 --- a/lustre/lov/lov_internal.h +++ b/lustre/lov/lov_internal.h @@ -221,8 +221,4 @@ int lov_getstripe(struct obd_export *exp, /* 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 diff --git a/lustre/lov/lov_log.c b/lustre/lov/lov_log.c index 722f42b..e92e430 100644 --- a/lustre/lov/lov_log.c +++ b/lustre/lov/lov_log.c @@ -61,8 +61,7 @@ * 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; @@ -75,16 +74,27 @@ static int lov_llog_origin_add(struct llog_ctxt *ctxt, 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); diff --git a/lustre/lov/lov_obd.c b/lustre/lov/lov_obd.c index 4a1b4375..c045db2 100644 --- a/lustre/lov/lov_obd.c +++ b/lustre/lov/lov_obd.c @@ -1292,6 +1292,7 @@ static int lov_ap_make_ready(void *data, int cmd) 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); @@ -1299,6 +1300,7 @@ static int lov_ap_refresh_count(void *data, int cmd) 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); @@ -1896,8 +1898,10 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len, break; default: { int set = 0; + if (count == 0) RETURN(-ENOTTY); + rc = 0; for (i = 0; i < count; i++) { int err; @@ -1908,7 +1912,9 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len, 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", @@ -2175,7 +2181,6 @@ int lov_complete_many(struct obd_export *exp, struct lov_stripe_md *lsm, } #endif - void lov_stripe_lock(struct lov_stripe_md *md) { LASSERT(md->lsm_lock_owner != current); @@ -2233,12 +2238,11 @@ struct obd_ops lov_obd_ops = { .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; @@ -2246,14 +2250,24 @@ int __init lov_init(void) 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); } diff --git a/lustre/lvfs/Makefile.in b/lustre/lvfs/Makefile.in index dc286b7..585f5a6 100644 --- a/lustre/lvfs/Makefile.in +++ b/lustre/lvfs/Makefile.in @@ -1,9 +1,7 @@ -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 diff --git a/lustre/lvfs/fsfilt_ext3.c b/lustre/lvfs/fsfilt_ext3.c index 25ada73..1b20288 100644 --- a/lustre/lvfs/fsfilt_ext3.c +++ b/lustre/lvfs/fsfilt_ext3.c @@ -1195,6 +1195,248 @@ static int fsfilt_ext3_get_op_len(int op, struct fsfilt_objinfo *fso, int logs) return 0; } +static const char *op_quotafile[] = { "lquota.user", "lquota.group" }; + +#define DQINFO_COPY(out, in) \ +do { \ + Q_COPY(out, in, dqi_bgrace); \ + 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) { @@ -1233,8 +1475,365 @@ static inline struct inode *ext3_iget_inuse(struct super_block *sb, 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 = { @@ -1260,9 +1859,9 @@ 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 diff --git a/lustre/mdc/mdc_internal.h b/lustre/mdc/mdc_internal.h index 8d79fe3..0d05129 100644 --- a/lustre/mdc/mdc_internal.h +++ b/lustre/mdc/mdc_internal.h @@ -70,25 +70,5 @@ static inline void mdc_put_rpc_lock(struct mdc_rpc_lock *lck, } /* 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; diff --git a/lustre/mdc/mdc_request.c b/lustre/mdc/mdc_request.c index 0783098..0fbdbc9 100644 --- a/lustre/mdc/mdc_request.c +++ b/lustre/mdc/mdc_request.c @@ -807,6 +807,7 @@ int mdc_readpage(struct obd_export *exp, struct ll_fid *mdc_fid, __u64 offset, return rc; } + static int mdc_iocontrol(unsigned int cmd, struct obd_export *exp, int len, void *karg, void *uarg) { @@ -849,7 +850,8 @@ static int mdc_iocontrol(unsigned int cmd, struct obd_export *exp, int len, } #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); @@ -1245,21 +1247,34 @@ struct obd_ops mdc_obd_ops = { .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); } diff --git a/lustre/mds/Makefile.in b/lustre/mds/Makefile.in index 25eb6f0..919c9aa 100644 --- a/lustre/mds/Makefile.in +++ b/lustre/mds/Makefile.in @@ -2,8 +2,4 @@ MODULES := mds 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@ diff --git a/lustre/mds/handler.c b/lustre/mds/handler.c index a07b147..0c331e2 100644 --- a/lustre/mds/handler.c +++ b/lustre/mds/handler.c @@ -207,7 +207,7 @@ struct dentry *mds_fid2dentry(struct mds_obd *mds, struct ll_fid *fid, 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. */ @@ -941,7 +941,7 @@ static int mds_obd_statfs(struct obd_device *obd, struct obd_statfs *osfs, 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); @@ -999,7 +999,7 @@ static int mds_sync(struct ptlrpc_request *req) 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; @@ -1203,6 +1203,48 @@ static int mds_set_info(struct obd_export *exp, struct ptlrpc_request *req) 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) { @@ -1411,13 +1453,13 @@ 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: @@ -1576,6 +1618,9 @@ static int mds_setup(struct obd_device *obd, obd_count len, void *buf) 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); @@ -1662,20 +1707,22 @@ static int mds_setup(struct obd_device *obd, obd_count len, void *buf) "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); @@ -1708,6 +1755,8 @@ static int mds_setup(struct obd_device *obd, obd_count len, void *buf) RETURN(0); +err_qctxt: + lquota_cleanup(quota_interface, obd); err_fs: /* No extra cleanup needed for llog_init_commit_thread() */ mds_fs_cleanup(obd); @@ -1719,7 +1768,7 @@ err_ns: 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); @@ -1806,6 +1855,9 @@ int mds_postrecov(struct obd_device *obd) /* 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); } @@ -1868,9 +1920,9 @@ static int mds_cleanup(struct obd_device *obd) 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; @@ -1879,7 +1931,7 @@ static int mds_cleanup(struct obd_device *obd) 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) { @@ -1905,7 +1957,7 @@ static int mds_cleanup(struct obd_device *obd) } mntput(mds->mds_vfsmnt); - mds->mds_sb = NULL; + obd->u.obt.obt_sb = NULL; ldlm_namespace_free(obd->obd_namespace, obd->obd_force); @@ -2307,15 +2359,23 @@ static struct obd_ops mdt_obd_ops = { .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); @@ -2326,7 +2386,9 @@ static int __init mds_init(void) 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); diff --git a/lustre/mds/lproc_mds.c b/lustre/mds/lproc_mds.c index 1964bc2..78d3e3f 100644 --- a/lustre/mds/lproc_mds.c +++ b/lustre/mds/lproc_mds.c @@ -224,6 +224,123 @@ static int lprocfs_wr_group_flush(struct file *file, const char *buffer, 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 }, diff --git a/lustre/mds/mds_fs.c b/lustre/mds/mds_fs.c index 3ff10d1..39bb8e9 100644 --- a/lustre/mds/mds_fs.c +++ b/lustre/mds/mds_fs.c @@ -416,9 +416,9 @@ int mds_fs_setup(struct obd_device *obd, struct vfsmount *mnt) 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; @@ -577,12 +577,12 @@ int mds_fs_cleanup(struct obd_device *obd) 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; } diff --git a/lustre/mds/mds_internal.h b/lustre/mds/mds_internal.h index 0c28e08..4f25fa4 100644 --- a/lustre/mds/mds_internal.h +++ b/lustre/mds/mds_internal.h @@ -205,89 +205,11 @@ int mds_pack_acl(struct mds_export_data *med, struct inode *inode, 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 */ diff --git a/lustre/mds/mds_log.c b/lustre/mds/mds_log.c index 5e2553d..b265d64 100644 --- a/lustre/mds/mds_log.c +++ b/lustre/mds/mds_log.c @@ -41,34 +41,9 @@ #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; @@ -77,7 +52,7 @@ static int mds_llog_origin_add(struct llog_ctxt *ctxt, 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); } @@ -139,8 +114,7 @@ int mds_log_op_unlink(struct obd_device *obd, struct inode *inode, 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)); @@ -179,8 +153,7 @@ int mds_log_op_setattr(struct obd_device *obd, struct inode *inode, /* 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: diff --git a/lustre/mds/mds_lov.c b/lustre/mds/mds_lov.c index b963109..900ee04 100644 --- a/lustre/mds/mds_lov.c +++ b/lustre/mds/mds_lov.c @@ -410,25 +410,25 @@ int mds_iocontrol(unsigned int cmd, struct obd_export *exp, int len, 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); } @@ -604,7 +604,14 @@ int mds_notify(struct obd_device *obd, struct obd_device *watched, int active) 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); } diff --git a/lustre/mds/mds_open.c b/lustre/mds/mds_open.c index 8e0d201..c7e40e6 100644 --- a/lustre/mds/mds_open.c +++ b/lustre/mds/mds_open.c @@ -307,7 +307,7 @@ cleanup_dentry: 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; @@ -668,7 +668,8 @@ static int accmode(struct inode *inode, int flags) /* 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; @@ -861,10 +862,11 @@ int mds_open(struct mds_update_record *rec, int offset, 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)); @@ -1099,7 +1101,7 @@ int mds_open(struct mds_update_record *rec, int offset, 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: @@ -1113,9 +1115,8 @@ int mds_open(struct mds_update_record *rec, int offset, } 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: @@ -1130,8 +1131,7 @@ int mds_open(struct mds_update_record *rec, int offset, } /* 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); } diff --git a/lustre/mds/mds_reint.c b/lustre/mds/mds_reint.c index ecc66bf..9fb6b3d 100644 --- a/lustre/mds/mds_reint.c +++ b/lustre/mds/mds_reint.c @@ -452,8 +452,9 @@ static int mds_reint_setattr(struct mds_update_record *rec, int offset, 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); @@ -487,8 +488,8 @@ static int mds_reint_setattr(struct mds_update_record *rec, int offset, 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) { @@ -533,8 +534,7 @@ static int mds_reint_setattr(struct mds_update_record *rec, int offset, } 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); @@ -657,11 +657,9 @@ static int mds_reint_setattr(struct mds_update_record *rec, int offset, 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; } @@ -702,8 +700,8 @@ static int mds_reint_create(struct mds_update_record *rec, int offset, 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; @@ -901,8 +899,8 @@ cleanup: * 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; } @@ -926,8 +924,7 @@ cleanup: 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; } @@ -1414,8 +1411,8 @@ static int mds_reint_unlink(struct mds_update_record *rec, int offset, 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); @@ -1448,10 +1445,10 @@ static int mds_reint_unlink(struct mds_update_record *rec, int offset, } /* 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 */ @@ -1625,7 +1622,7 @@ cleanup: 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; } @@ -1983,6 +1980,8 @@ static int mds_reint_rename(struct mds_update_record *rec, int offset, 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); @@ -2032,6 +2031,14 @@ static int mds_reint_rename(struct mds_update_record *rec, int offset, 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)); @@ -2139,6 +2146,9 @@ cleanup: LBUG(); } req->rq_status = rc; + + /* acquire/release qunit */ + lquota_adjust(quota_interface, obd, qcids, qpids, rc, FSFILT_OP_RENAME); return 0; } diff --git a/lustre/mds/quota_context.c b/lustre/mds/quota_context.c deleted file mode 100644 index 1672bb2..0000000 --- a/lustre/mds/quota_context.c +++ /dev/null @@ -1,584 +0,0 @@ -/* -*- 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 - * - * 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 -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -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); diff --git a/lustre/obdclass/genops.c b/lustre/obdclass/genops.c index 79c730a..043714d 100644 --- a/lustre/obdclass/genops.c +++ b/lustre/obdclass/genops.c @@ -36,7 +36,6 @@ #include #include #include -#include extern struct list_head obd_types; static spinlock_t obd_types_lock = SPIN_LOCK_UNLOCKED; @@ -45,16 +44,6 @@ kmem_cache_t *obdo_cachep = NULL; 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); @@ -365,25 +354,6 @@ struct obd_device * class_devices_in_group(struct obd_uuid *grp_uuid, int *next) 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) { @@ -398,35 +368,11 @@ 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); @@ -442,10 +388,6 @@ int obd_init_caches(void) if (!import_cachep) GOTO(out, -ENOMEM); - rc = obd_init_qunit_cache(); - if (rc) - GOTO(out, rc); - RETURN(0); out: obd_cleanup_caches(); diff --git a/lustre/obdclass/llog_obd.c b/lustre/obdclass/llog_obd.c index 11e41dd..0e64454 100644 --- a/lustre/obdclass/llog_obd.c +++ b/lustre/obdclass/llog_obd.c @@ -106,7 +106,7 @@ EXPORT_SYMBOL(llog_sync); 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; @@ -118,7 +118,7 @@ int llog_add(struct llog_ctxt *ctxt, struct llog_rec_hdr *rec, 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); @@ -283,8 +283,7 @@ EXPORT_SYMBOL(llog_obd_origin_cleanup); /* 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; diff --git a/lustre/obdfilter/filter.c b/lustre/obdfilter/filter.c index ef684b6..3aba587 100644 --- a/lustre/obdfilter/filter.c +++ b/lustre/obdfilter/filter.c @@ -1406,7 +1406,7 @@ int filter_common_setup(struct obd_device *obd, obd_count len, void *buf, } 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); @@ -1459,10 +1459,9 @@ int filter_common_setup(struct obd_device *obd, obd_count len, void *buf, 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 " @@ -1493,7 +1492,7 @@ err_post: 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); @@ -1508,6 +1507,9 @@ static int filter_setup(struct obd_device *obd, obd_count len, void *buf) 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); @@ -1629,22 +1631,22 @@ static int filter_cleanup(struct obd_device *obd) 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", @@ -1659,8 +1661,8 @@ static int filter_cleanup(struct obd_device *obd) } 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); @@ -1881,7 +1883,7 @@ static int filter_disconnect(struct obd_export *exp) 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); @@ -1951,11 +1953,10 @@ static int filter_getattr(struct obd_export *exp, struct obdo *oa, 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; @@ -1977,8 +1978,8 @@ int filter_setattr_internal(struct obd_export *exp, struct dentry *dentry, 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 { @@ -2017,17 +2018,12 @@ out_unlock: 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; } @@ -2141,7 +2137,7 @@ static int filter_statfs(struct obd_device *obd, struct obd_statfs *osfs, 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; @@ -2149,7 +2145,7 @@ static int filter_statfs(struct obd_device *obd, struct obd_statfs *osfs, * 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); @@ -2168,7 +2164,8 @@ static int filter_statfs(struct obd_device *obd, struct obd_statfs *osfs, /* 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); } @@ -2351,6 +2348,7 @@ filter_destroy_internal(struct obd_export *exp, struct obdo *oa, 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; @@ -2459,12 +2457,12 @@ cleanup: } /* 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); } @@ -2596,7 +2594,7 @@ static int filter_create(struct obd_export *exp, struct obdo *oa, struct filter_obd *filter; obd_gr group = oa->o_gr; struct obd_device *obd; - int rc; + int rc = 0; ENTRY; obd = exp->exp_obd; @@ -2636,7 +2634,7 @@ static int filter_create(struct obd_export *exp, struct obdo *oa, 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; } @@ -2701,7 +2699,7 @@ static int filter_sync(struct obd_export *exp, struct obdo *oa, /* 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); @@ -2754,7 +2752,7 @@ static int filter_get_info(struct obd_export *exp, __u32 keylen, 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); } @@ -2762,7 +2760,7 @@ static int filter_get_info(struct obd_export *exp, __u32 keylen, 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); } @@ -2801,8 +2799,8 @@ static int filter_set_info(struct obd_export *exp, __u32 keylen, /* 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); } @@ -2823,13 +2821,13 @@ int filter_iocontrol(unsigned int cmd, struct obd_export *exp, 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", @@ -2840,9 +2838,9 @@ int filter_iocontrol(unsigned int cmd, struct obd_export *exp, 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); } @@ -2877,14 +2875,13 @@ int filter_iocontrol(unsigned int cmd, struct obd_export *exp, 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; @@ -2924,8 +2921,6 @@ static struct obd_ops filter_obd_ops = { .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, }; @@ -2956,6 +2951,9 @@ static struct obd_ops filter_sanobd_ops = { .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; @@ -2971,6 +2969,10 @@ static int __init obdfilter_init(void) 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) @@ -2981,15 +2983,22 @@ static int __init obdfilter_init(void) 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, diff --git a/lustre/obdfilter/filter_internal.h b/lustre/obdfilter/filter_internal.h index dbbf1df..a2c2267 100644 --- a/lustre/obdfilter/filter_internal.h +++ b/lustre/obdfilter/filter_internal.h @@ -194,71 +194,6 @@ static inline int lproc_filter_attach_seqstat(struct obd_device *dev) {} #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 */ diff --git a/lustre/obdfilter/filter_io.c b/lustre/obdfilter/filter_io.c index b9ca816..0b68a84 100644 --- a/lustre/obdfilter/filter_io.c +++ b/lustre/obdfilter/filter_io.c @@ -152,7 +152,7 @@ static void filter_grant_incoming(struct obd_export *exp, struct obdo *oa) 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; @@ -160,7 +160,7 @@ obd_size filter_grant_space_left(struct obd_export *exp) 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; @@ -209,7 +209,7 @@ long filter_grant(struct obd_export *exp, obd_size current_grant, { 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); @@ -391,7 +391,7 @@ static int filter_grant_check(struct obd_export *exp, int objcount, 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; @@ -465,7 +465,7 @@ static int filter_grant_check(struct obd_export *exp, int objcount, /* 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 diff --git a/lustre/obdfilter/filter_io_26.c b/lustre/obdfilter/filter_io_26.c index a712188..1ab866c 100644 --- a/lustre/obdfilter/filter_io_26.c +++ b/lustre/obdfilter/filter_io_26.c @@ -53,6 +53,7 @@ struct dio_request { 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; }; @@ -439,6 +440,8 @@ int filter_direct_io(int rw, struct dentry *dchild, void *iobuf, 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, @@ -453,7 +456,8 @@ remap: * 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; } @@ -528,10 +532,9 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa, 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); @@ -548,6 +551,7 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa, 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; @@ -571,16 +575,15 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa, 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); @@ -609,7 +612,7 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa, 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"); @@ -629,9 +632,7 @@ cleanup: 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); @@ -644,11 +645,12 @@ cleanup: } /* 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); } diff --git a/lustre/obdfilter/filter_log.c b/lustre/obdfilter/filter_log.c index 87a2e2a..390a293 100644 --- a/lustre/obdfilter/filter_log.c +++ b/lustre/obdfilter/filter_log.c @@ -116,8 +116,7 @@ void filter_cancel_cookies_cb(struct obd_device *obd, __u64 transno, } /* 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) @@ -155,8 +154,7 @@ static int filter_recov_log_unlink_cb(struct llog_ctxt *ctxt, } /* 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) diff --git a/lustre/obdfilter/lproc_obdfilter.c b/lustre/obdfilter/lproc_obdfilter.c index 397009e..88da264 100644 --- a/lustre/obdfilter/lproc_obdfilter.c +++ b/lustre/obdfilter/lproc_obdfilter.c @@ -120,6 +120,123 @@ int lprocfs_filter_wr_readcache(struct file *file, const char *buffer, 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 }, @@ -151,7 +268,6 @@ static struct lprocfs_vars lprocfs_obd_vars[] = { { "quota_itune_sz", lprocfs_filter_rd_itune, lprocfs_filter_wr_itune, 0}, #endif - { 0 } }; diff --git a/lustre/osc/osc_internal.h b/lustre/osc/osc_internal.h index 6c6d385..82db660 100644 --- a/lustre/osc/osc_internal.h +++ b/lustre/osc/osc_internal.h @@ -57,55 +57,9 @@ int osc_real_create(struct obd_export *exp, struct obdo *oa, 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); diff --git a/lustre/osc/osc_quota.c b/lustre/osc/osc_quota.c deleted file mode 100644 index 60446b2..0000000 --- a/lustre/osc/osc_quota.c +++ /dev/null @@ -1,326 +0,0 @@ -/* -*- 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 -# include -# include -# include -# include -# include -# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) -# include -# include -# else -# include -# endif -#else -# include -#endif - -#include -#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); -} - diff --git a/lustre/osc/osc_request.c b/lustre/osc/osc_request.c index 5996720..f83f25f 100644 --- a/lustre/osc/osc_request.c +++ b/lustre/osc/osc_request.c @@ -938,8 +938,9 @@ static int osc_brw_fini_request(struct ptlrpc_request *req, struct obdo *oa, /* 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); @@ -2045,7 +2046,8 @@ static int osc_queue_async_io(struct obd_export *exp, struct lov_stripe_md *lsm, 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); @@ -2874,6 +2876,7 @@ static int osc_getstripe(struct lov_stripe_md *lsm, struct lov_user_md *lump) RETURN(rc); } + static int osc_iocontrol(unsigned int cmd, struct obd_export *exp, int len, void *karg, void *uarg) { @@ -2949,7 +2952,8 @@ static int osc_iocontrol(unsigned int cmd, struct obd_export *exp, int len, 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", @@ -3264,7 +3268,7 @@ int osc_cleanup(struct obd_device *obd) 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); @@ -3314,8 +3318,6 @@ struct obd_ops osc_obd_ops = { .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)) @@ -3351,6 +3353,9 @@ struct obd_ops sanosc_obd_ops = { }; #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; @@ -3365,27 +3370,39 @@ int __init osc_init(void) 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 diff --git a/lustre/ost/ost_handler.c b/lustre/ost/ost_handler.c index cc54ac0..3c534d0 100644 --- a/lustre/ost/ost_handler.c +++ b/lustre/ost/ost_handler.c @@ -1075,6 +1075,50 @@ static int ost_get_info(struct obd_export *exp, struct ptlrpc_request *req) 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) { @@ -1242,12 +1286,12 @@ static int ost_handle(struct ptlrpc_request *req) 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"); @@ -1516,14 +1560,17 @@ static struct obd_ops ost_obd_ops = { .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) diff --git a/lustre/ost/ost_internal.h b/lustre/ost/ost_internal.h index 9c7fecc..51ae8c9 100644 --- a/lustre/ost/ost_internal.h +++ b/lustre/ost/ost_internal.h @@ -45,21 +45,7 @@ struct ost_thread_local_cache { 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 */ diff --git a/lustre/ptlrpc/Makefile.in b/lustre/ptlrpc/Makefile.in index ac1a021..244925b 100644 --- a/lustre/ptlrpc/Makefile.in +++ b/lustre/ptlrpc/Makefile.in @@ -16,10 +16,6 @@ ptlrpc_objs += pers.o lproc_ptlrpc.o 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 diff --git a/lustre/ptlrpc/llog_net.c b/lustre/ptlrpc/llog_net.c index 0e08bb6..bdd8dbb 100644 --- a/lustre/ptlrpc/llog_net.c +++ b/lustre/ptlrpc/llog_net.c @@ -74,7 +74,7 @@ int llog_origin_connect(struct llog_ctxt *ctxt, int count, 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); diff --git a/lustre/quota/.cvsignore b/lustre/quota/.cvsignore new file mode 100644 index 0000000..d5103fa --- /dev/null +++ b/lustre/quota/.cvsignore @@ -0,0 +1,15 @@ +.Xrefs +config.log +config.status +configure +Makefile +.deps +TAGS +.*.cmd +autoMakefile.in +autoMakefile +*.ko +*.mod.c +.*.o.flags +.tmp_versions +.depend diff --git a/lustre/quota/Makefile.in b/lustre/quota/Makefile.in new file mode 100644 index 0000000..19a37ca --- /dev/null +++ b/lustre/quota/Makefile.in @@ -0,0 +1,10 @@ +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@ + diff --git a/lustre/quota/autoMakefile.am b/lustre/quota/autoMakefile.am new file mode 100644 index 0000000..c23c370 --- /dev/null +++ b/lustre/quota/autoMakefile.am @@ -0,0 +1,19 @@ +# 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 diff --git a/lustre/quota/quota_check.c b/lustre/quota/quota_check.c new file mode 100644 index 0000000..55a33a6 --- /dev/null +++ b/lustre/quota/quota_check.c @@ -0,0 +1,245 @@ +/* -*- 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 +# include +# include +# include +# include +# include +# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) +# include +# include +# include +# include +# else +# include +# endif +#else /* __KERNEL__ */ +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#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); +} diff --git a/lustre/quota/quota_context.c b/lustre/quota/quota_context.c new file mode 100644 index 0000000..ed1ff48 --- /dev/null +++ b/lustre/quota/quota_context.c @@ -0,0 +1,797 @@ +/* -*- 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 + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#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; +} + diff --git a/lustre/quota/quota_ctl.c b/lustre/quota/quota_ctl.c new file mode 100644 index 0000000..3414763 --- /dev/null +++ b/lustre/quota/quota_ctl.c @@ -0,0 +1,255 @@ +/* -*- 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 +# include +# include +# include +# include +# include +# include +# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) +# include +# include +# include +# include +# else +# include +# endif +#else /* __KERNEL__ */ +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#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); +} + diff --git a/lustre/quota/quota_interface.c b/lustre/quota/quota_interface.c new file mode 100644 index 0000000..6085ff3 --- /dev/null +++ b/lustre/quota/quota_interface.c @@ -0,0 +1,693 @@ +/* -*- 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 +# include +# include +# include +# include +# include +# include +# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) +# include +# include +# include +# include +# else +# include +# endif +#else /* __KERNEL__ */ +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#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. "); +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 */ diff --git a/lustre/quota/quota_internal.h b/lustre/quota/quota_internal.h new file mode 100644 index 0000000..0389734 --- /dev/null +++ b/lustre/quota/quota_internal.h @@ -0,0 +1,91 @@ +/* -*- 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 + +/* 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 diff --git a/lustre/mds/quota_master.c b/lustre/quota/quota_master.c similarity index 56% rename from lustre/mds/quota_master.c rename to lustre/quota/quota_master.c index 36c27e0..1a72640 100644 --- a/lustre/mds/quota_master.c +++ b/lustre/quota/quota_master.c @@ -1,10 +1,10 @@ /* -*- 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 * * This file is part of Lustre, http://www.lustre.org. @@ -32,8 +32,10 @@ #include #include -#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; @@ -67,8 +69,9 @@ void lustre_dquot_exit(void) 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; @@ -82,17 +85,16 @@ static inline int const dquot_hashfn(struct lustre_quota_info *info, 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); @@ -111,12 +113,12 @@ static struct lustre_dquot *alloc_dquot(struct lustre_quota_info *lqi, 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); } @@ -130,6 +132,7 @@ static void insert_dquot_nolock(struct lustre_dquot *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); } @@ -143,8 +146,9 @@ static void lustre_dqput(struct lustre_dquot *dquot) { 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); } @@ -152,64 +156,41 @@ static void lustre_dqput(struct lustre_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); } @@ -225,6 +206,8 @@ int dqacq_handler(struct obd_device *obd, struct qunit_data *qdata, int opc) 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); @@ -235,9 +218,14 @@ int dqacq_handler(struct obd_device *obd, struct qunit_data *qdata, int opc) 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; @@ -250,7 +238,7 @@ int dqacq_handler(struct obd_device *obd, struct qunit_data *qdata, int opc) 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 */ @@ -258,63 +246,126 @@ int dqacq_handler(struct obd_device *obd, struct qunit_data *qdata, int opc) 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; @@ -330,10 +381,10 @@ int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl) 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; @@ -348,14 +399,14 @@ int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl) /* 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", @@ -365,12 +416,13 @@ int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl) 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); @@ -378,7 +430,7 @@ int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl) } 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; @@ -388,35 +440,52 @@ int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl) 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; @@ -424,82 +493,106 @@ int mds_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl) } 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); } @@ -508,25 +601,28 @@ int mds_get_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; 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; @@ -536,18 +632,18 @@ static int mds_init_slave_ilimits(struct obd_device *obd, 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); @@ -557,15 +653,16 @@ static int mds_init_slave_ilimits(struct obd_device *obd, 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, @@ -581,18 +678,18 @@ 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); @@ -602,18 +699,18 @@ static int mds_init_slave_blimits(struct obd_device *obd, 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) @@ -624,21 +721,28 @@ 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; @@ -646,6 +750,11 @@ int mds_set_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl) 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; @@ -653,6 +762,15 @@ int mds_set_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl) 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) { @@ -662,27 +780,30 @@ int mds_set_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl) 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; } } @@ -690,14 +811,14 @@ int mds_set_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl) 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; @@ -707,31 +828,52 @@ revoke_out: 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; } @@ -744,12 +886,13 @@ int mds_get_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl) 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; @@ -760,11 +903,190 @@ int mds_get_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl) 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); } diff --git a/lustre/lvfs/quotacheck_test.c b/lustre/quota/quotacheck_test.c similarity index 85% rename from lustre/lvfs/quotacheck_test.c rename to lustre/quota/quotacheck_test.c index 87c9b7b..0c88030 100644 --- a/lustre/lvfs/quotacheck_test.c +++ b/lustre/quota/quotacheck_test.c @@ -1,7 +1,7 @@ /* -*- 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 * * This file is part of Lustre, http://www.lustre.org/ @@ -40,12 +40,12 @@ get_group_desc(struct super_block *sb, int group) { 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; } @@ -54,10 +54,10 @@ read_inode_bitmap(struct super_block *sb, unsigned long group) { 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; } @@ -66,13 +66,13 @@ static inline struct inode *ext3_iget_inuse(struct super_block *sb, 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; } @@ -104,7 +104,7 @@ static int quotacheck_test_1(struct obd_device *obd, struct super_block *sb) 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)); @@ -133,20 +133,16 @@ static int quotacheck_test_1(struct obd_device *obd, struct super_block *sb) * ------------------------------------------------------------------------- */ 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; } diff --git a/lustre/lvfs/quotactl_test.c b/lustre/quota/quotactl_test.c similarity index 94% rename from lustre/lvfs/quotactl_test.c rename to lustre/quota/quotactl_test.c index 1e03388..0ac332c 100644 --- a/lustre/lvfs/quotactl_test.c +++ b/lustre/quota/quotactl_test.c @@ -1,7 +1,7 @@ /* -*- 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 * * This file is part of Lustre, http://www.lustre.org/ @@ -24,12 +24,11 @@ #include #include -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; @@ -37,12 +36,9 @@ static int quotactl_test_1(struct obd_device *obd, struct super_block *sb) 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 */ @@ -88,7 +84,6 @@ static int quotactl_test_2(struct obd_device *obd, struct super_block *sb) /* Test set/getquota */ static int quotactl_test_3(struct obd_device *obd, struct super_block *sb) { - struct obd_quotactl oqctl; int rc; ENTRY; @@ -236,7 +231,6 @@ static int quotactl_test_3(struct obd_device *obd, struct super_block *sb) /* Test quotaoff */ static int quotactl_test_4(struct obd_device *obd, struct super_block *sb) { - struct obd_quotactl oqctl; int rc; ENTRY; @@ -262,15 +256,14 @@ static int quotactl_run_tests(struct obd_device *obd, struct obd_device *tgt) 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); diff --git a/lustre/tests/Makefile.am b/lustre/tests/Makefile.am index 9c33b51..f124768 100644 --- a/lustre/tests/Makefile.am +++ b/lustre/tests/Makefile.am @@ -18,7 +18,7 @@ if TESTS 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 diff --git a/lustre/tests/chownmany.c b/lustre/tests/chownmany.c new file mode 100644 index 0000000..64512ef --- /dev/null +++ b/lustre/tests/chownmany.c @@ -0,0 +1,79 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; +} diff --git a/lustre/tests/llog-test.sh b/lustre/tests/llog-test.sh new file mode 100644 index 0000000..4044610 --- /dev/null +++ b/lustre/tests/llog-test.sh @@ -0,0 +1,102 @@ +#!/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 diff --git a/lustre/tests/local.sh b/lustre/tests/local.sh index 3207c18..ced41d2 100755 --- a/lustre/tests/local.sh +++ b/lustre/tests/local.sh @@ -66,8 +66,12 @@ ${LMC} --add net --node client --nid '*' --nettype $NETTYPE || exit 12 [ "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" ] && @@ -78,7 +82,7 @@ ${LMC} --add lov --lov lov1 --mds mds1 --stripe_sz $STRIPE_BYTES \ --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 diff --git a/lustre/tests/lov.sh b/lustre/tests/lov.sh index fbf563f..7130ad0 100755 --- a/lustre/tests/lov.sh +++ b/lustre/tests/lov.sh @@ -42,12 +42,15 @@ ${LMC} --add node --node $HOSTNAME || exit 10 ${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 \ @@ -58,7 +61,7 @@ for num in `seq $OSTCOUNT`; do 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 diff --git a/lustre/tests/quota_sanity.sh b/lustre/tests/quota_sanity.sh deleted file mode 100644 index 59f1b72..0000000 --- a/lustre/tests/quota_sanity.sh +++ /dev/null @@ -1,446 +0,0 @@ -#!/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 diff --git a/lustre/tests/sanity-quota.sh b/lustre/tests/sanity-quota.sh new file mode 100644 index 0000000..f3911c8 --- /dev/null +++ b/lustre/tests/sanity-quota.sh @@ -0,0 +1,666 @@ +#!/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 + diff --git a/lustre/utils/lconf b/lustre/utils/lconf index 7fc574d..398d463 100755 --- a/lustre/utils/lconf +++ b/lustre/utils/lconf @@ -1134,6 +1134,7 @@ class MDSDEV(Module): 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) @@ -1189,6 +1190,8 @@ class MDSDEV(Module): 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') @@ -1238,7 +1241,8 @@ class MDSDEV(Module): 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) @@ -1391,6 +1395,7 @@ class OSD(Module): 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': @@ -1421,6 +1426,8 @@ class OSD(Module): 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': @@ -1470,8 +1477,9 @@ class OSD(Module): 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 ="") @@ -1749,6 +1757,10 @@ class Mountpoint(Module): 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') diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index ae1332c..79a3c58 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -32,6 +32,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -46,25 +50,6 @@ 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); @@ -73,7 +58,7 @@ static int lfs_osts(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); @@ -111,9 +96,9 @@ command_t cmdlist[] = { "\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] \n" + {"quotachown",lfs_quotachown, 0, + "Change files' owner or group on the specified filesystem.\n" + "usage: quotachown [-i] \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" @@ -127,8 +112,7 @@ command_t cmdlist[] = { "usage: setquota [ -u | -g ] \n" " setquota -t [ -u | -g ] "}, {"quota", lfs_quota, 0, "Display disk usage and limits.\n" - "usage: quota -t [ -u |-g ] \n" - " quota [ -o obd_uuid ] [ -u | -g ] [name] "}, + "usage: quota [ -o obd_uuid ] [ -u | -g ] [name] "}, #endif {"help", Parser_help, 0, "help"}, {"exit", Parser_quit, 0, "quit"}, @@ -438,7 +422,7 @@ 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) { int c,rc; @@ -450,13 +434,14 @@ static int lfs_quotachog(int argc, char **argv) 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; @@ -485,7 +470,8 @@ static int lfs_quotacheck(int argc, char **argv) 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; } } @@ -561,7 +547,8 @@ static int lfs_quotaon(int argc, char **argv) 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; } } @@ -607,7 +594,8 @@ static int lfs_quotaoff(int argc, char **argv) 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; } } @@ -720,7 +708,8 @@ int lfs_setquota(int argc, char **argv) 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; } } @@ -729,12 +718,13 @@ int lfs_setquota(int argc, char **argv) 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; @@ -750,8 +740,10 @@ int lfs_setquota(int argc, char **argv) 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; @@ -813,8 +805,18 @@ static void diff2str(time_t seconds, char *buf, time_t now) 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; @@ -822,7 +824,7 @@ static void print_quota(char *mnt, char *name, struct if_quotactl *qctl) 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) { @@ -848,14 +850,6 @@ static void print_quota(char *mnt, 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"); - #if 0 /* XXX: always print quotas even when no usages */ if (dqb->dqb_curspace || dqb->dqb_curinodes) #endif @@ -867,29 +861,92 @@ static void print_quota(char *mnt, char *name, struct if_quotactl *qctl) 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) @@ -920,7 +977,8 @@ 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; } } @@ -929,11 +987,15 @@ static int lfs_quota(int argc, char **argv) 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) { @@ -941,6 +1003,7 @@ static int lfs_quota(int argc, char **argv) name, strerror(errno)); return CMD_HELP; } + print_quota_title(name, &qctl); } else if (optind + 1 != argc) { return CMD_HELP; } @@ -958,7 +1021,18 @@ static int lfs_quota(int argc, char **argv) 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 */ diff --git a/lustre/utils/liblustreapi.c b/lustre/utils/liblustreapi.c index 67fc615..f40162b 100644 --- a/lustre/utils/liblustreapi.c +++ b/lustre/utils/liblustreapi.c @@ -56,6 +56,7 @@ #include #include #include +#include static void err_msg(char *fmt, ...) { @@ -654,7 +655,7 @@ int llapi_ping(char *obd_type, char *obd_name) 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"); @@ -669,6 +670,7 @@ int llapi_target_check(int type_num, char **obd_type, char *dir) 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; @@ -682,6 +684,7 @@ int llapi_target_check(int type_num, char **obd_type, char *dir) obd_type_name = strsep(&bufp, " "); } obd_name = strsep(&bufp, " "); + obd_uuid = strsep(&bufp, " "); memset(&osfs_buffer, 0, sizeof (osfs_buffer)); @@ -693,19 +696,32 @@ int llapi_target_check(int type_num, char **obd_type, char *dir) 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) @@ -785,7 +801,7 @@ int llapi_poll_quotacheck(char *mnt, struct if_quotacheck *qchk) 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) @@ -813,7 +829,7 @@ int llapi_quotactl(char *mnt, struct if_quotactl *qctl) 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; @@ -839,6 +855,10 @@ static int quotachog_process_file(DIR *dir, char *dname, char *fname, 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", @@ -846,7 +866,7 @@ static int quotachog_process_file(DIR *dir, char *dname, char *fname, return rc; } -int llapi_quotachog(char *path, int flag) +int llapi_quotachown(char *path, int flag) { struct find_param param; int ret = 0; @@ -855,7 +875,7 @@ int llapi_quotachog(char *path, int flag) 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) diff --git a/lustre/utils/lmc b/lustre/utils/lmc index d0c19db..d584d29 100755 --- a/lustre/utils/lmc +++ b/lustre/utils/lmc @@ -95,6 +95,7 @@ Object creation command summary: --mdsuuid uuid --mkfsoptions options --mountfsoptions options + --quota quotaon=u|g|ug,iunit=,bunit=,itune=,btune= --add lov --lov lov_name @@ -118,6 +119,7 @@ Object creation command summary: --ostuuid uuid --mkfsoptions options --mountfsoptions options + --quota quotaon=u|g|ug,iunit=,bunit=,itune=,btune= --add mtpt - Mountpoint --node node_name @@ -199,7 +201,19 @@ lmc_options = [ ('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), @@ -383,7 +397,7 @@ class GenConfig: 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)) @@ -403,6 +417,8 @@ class GenConfig: 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 @@ -446,7 +462,7 @@ class GenConfig: 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) @@ -463,6 +479,8 @@ class GenConfig: 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) @@ -760,6 +778,7 @@ def add_mds(gen, lustre, options): 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') @@ -773,7 +792,7 @@ def add_mds(gen, lustre, options): 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) @@ -792,7 +811,8 @@ def add_ost(gen, lustre, options): journal_size = '' inode_size = '' mkfsoptions = '' - mountfsoptions = '' + mountfsoptions = '' + quota = '' else: devname = get_option(options, 'dev') # can be unset for bluearcs size = get_option(options, 'size') @@ -800,7 +820,8 @@ def add_ost(gen, lustre, options): 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') @@ -839,7 +860,7 @@ def add_ost(gen, lustre, options): 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") diff --git a/lustre/utils/lustre_cfg.c b/lustre/utils/lustre_cfg.c index 755973c..eea50e4 100644 --- a/lustre/utils/lustre_cfg.c +++ b/lustre/utils/lustre_cfg.c @@ -157,7 +157,7 @@ int jt_lcfg_setup(int argc, char **argv) lustre_cfg_bufs_reset(&bufs, lcfg_devname); - if (argc > 5) + if (argc > 6) return CMD_HELP; for (i = 1; i < argc; i++) {