diff options
Diffstat (limited to 'lib/quota')
-rw-r--r-- | lib/quota/Makefile.in | 85 | ||||
-rw-r--r-- | lib/quota/common.h | 20 | ||||
-rw-r--r-- | lib/quota/dqblk_v2.h | 22 | ||||
-rw-r--r-- | lib/quota/mkquota.c | 216 | ||||
-rw-r--r-- | lib/quota/mkquota.h | 63 | ||||
-rw-r--r-- | lib/quota/quota.h | 155 | ||||
-rw-r--r-- | lib/quota/quota.pc.in | 11 | ||||
-rw-r--r-- | lib/quota/quotaio.c | 127 | ||||
-rw-r--r-- | lib/quota/quotaio.h | 119 | ||||
-rw-r--r-- | lib/quota/quotaio_tree.c | 80 | ||||
-rw-r--r-- | lib/quota/quotaio_tree.h | 13 | ||||
-rw-r--r-- | lib/quota/quotaio_v2.c | 56 | ||||
-rw-r--r-- | lib/quota/quotaio_v2.h | 91 |
13 files changed, 458 insertions, 600 deletions
diff --git a/lib/quota/Makefile.in b/lib/quota/Makefile.in index 5a12d4f9..92df2681 100644 --- a/lib/quota/Makefile.in +++ b/lib/quota/Makefile.in @@ -12,9 +12,6 @@ INSTALL = @INSTALL@ all:: -SMANPAGES= - - OBJS= mkquota.o quotaio.o quotaio_v2.o quotaio_tree.o dict.o SRCS= $(srcdir)/mkquota.c \ @@ -31,7 +28,7 @@ LIBDIR= quota #ELF_IMAGE = libquota #ELF_MYDIR = quota #ELF_INSTALL_DIR = $(root_libdir) -#ELF_OTHER_LIBS = -L../.. -lext2fs +#ELF_OTHER_LIBS = -lext2fs #BSDLIB_VERSION = 1.0 #BSDLIB_IMAGE = libquota @@ -47,17 +44,12 @@ LIBDIR= quota .c.o: $(E) " CC $<" $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ + $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $< @PROFILE_CMT@ $(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/$*.o -c $< @CHECKER_CMT@ $(Q) $(CC) $(ALL_CFLAGS) -checker -g -o checker/$*.o -c $< #ELF_CMT# $(Q) $(CC) $(ALL_CFLAGS) -fPIC -o elfshared/$*.o -c $< #BSDLIB_CMT# $(Q) $(CC) $(ALL_CFLAGS) $(BSDLIB_PIC_FLAG) -o pic/$*.o -c $< -all:: $(SMANPAGES) quota.pc - -quota.pc: $(srcdir)/quota.pc.in $(top_builddir)/config.status - $(E) " CONFIG.STATUS $@" - $(Q) cd $(top_builddir); CONFIG_FILES=lib/quota/quota.pc ./config.status - dict.o: $(E) " CC $<" $(Q) $(CC) -c $(ALL_CFLAGS) $(top_srcdir)/e2fsck/dict.c -o $@ @@ -71,32 +63,10 @@ dict.o: #BSDLIB_CMT# $(top_srcdir)/e2fsck/dict.c installdirs:: - $(E) " MKINSTALLDIRS $(libdir) $(includedir)/quota $(man3dir)" - $(Q) $(MKINSTALLDIRS) $(DESTDIR)$(libdir) \ - $(DESTDIR)$(includedir)/quota $(DESTDIR)$(man3dir) \ - $(DESTDIR)$(libdir)/pkgconfig - -install:: all installdirs - $(E) " INSTALL_DATA $(libdir)/libquota.a" - $(Q) $(INSTALL_DATA) libquota.a $(DESTDIR)$(libdir)/libquota.a - -$(Q) $(RANLIB) $(DESTDIR)$(libdir)/libquota.a - $(Q) $(CHMOD) $(LIBMODE) $(DESTDIR)$(libdir)/libquota.a - $(E) " INSTALL_DATA $(includedir)/quota/mkquota.h" - $(Q) $(INSTALL_DATA) $(srcdir)/mkquota.h $(DESTDIR)$(includedir)/quota/mkquota.h - $(Q) for i in $(SMANPAGES); do \ - $(RM) -f $(DESTDIR)$(man3dir)/$$i.gz; \ - echo " INSTALL_DATA $(man3dir)/$$i"; \ - $(INSTALL_DATA) $$i $(DESTDIR)$(man3dir)/$$i; \ - done - $(E) " INSTALL_DATA $(libdir)/pkgconfig/quota.pc" - $(Q) $(INSTALL_DATA) quota.pc $(DESTDIR)$(libdir)/pkgconfig/quota.pc + +install:: all uninstall:: - $(RM) -f $(DESTDIR)$(libdir)/libquota.a \ - $(DESTDIR)$(libdir)/pkgconfig/quota.pc - for i in $(SMANPAGES); do \ - $(RM) -f $(DESTDIR)$(man3dir)/$$i; \ - done clean:: $(RM) -f \#* *.s *.o *.a *~ *.bak core profiled/* checker/* @@ -107,7 +77,7 @@ clean:: mostlyclean:: clean distclean:: clean - $(RM) -f .depend Makefile quota.pc \ + $(RM) -f .depend Makefile \ $(srcdir)/TAGS $(srcdir)/Makefile.in.old # @@ -130,33 +100,36 @@ mkquota.o: $(srcdir)/mkquota.c $(top_builddir)/lib/config.h \ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \ - $(top_srcdir)/lib/e2p/e2p.h $(srcdir)/quota.h $(srcdir)/quotaio.h \ - $(srcdir)/dqblk_v2.h $(srcdir)/quotaio_tree.h $(srcdir)/quotaio_v2.h \ - $(srcdir)/mkquota.h $(top_srcdir)/lib/../e2fsck/dict.h $(srcdir)/common.h + $(top_srcdir)/lib/e2p/e2p.h $(srcdir)/quotaio.h $(srcdir)/dqblk_v2.h \ + $(srcdir)/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h \ + $(srcdir)/quotaio_v2.h $(srcdir)/common.h quotaio.o: $(srcdir)/quotaio.c $(top_builddir)/lib/config.h \ - $(top_builddir)/lib/dirpaths.h $(srcdir)/common.h $(srcdir)/quotaio.h \ - $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \ - $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \ - $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \ - $(top_builddir)/lib/ext2fs/ext2_err.h \ + $(top_builddir)/lib/dirpaths.h $(srcdir)/common.h \ + $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/quotaio.h \ + $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_srcdir)/lib/ext2fs/ext2fs.h \ + $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \ + $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \ - $(srcdir)/quota.h $(srcdir)/dqblk_v2.h $(srcdir)/quotaio_tree.h + $(srcdir)/dqblk_v2.h $(srcdir)/quotaio_tree.h \ + $(top_srcdir)/lib/../e2fsck/dict.h quotaio_tree.o: $(srcdir)/quotaio_tree.c $(top_builddir)/lib/config.h \ - $(top_builddir)/lib/dirpaths.h $(srcdir)/common.h $(srcdir)/quotaio_tree.h \ - $(srcdir)/quota.h $(top_builddir)/lib/ext2fs/ext2_types.h \ - $(srcdir)/quotaio.h $(top_srcdir)/lib/ext2fs/ext2fs.h \ - $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \ + $(top_builddir)/lib/dirpaths.h $(srcdir)/common.h \ + $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/quotaio_tree.h \ + $(srcdir)/quotaio.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \ + $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \ $(top_builddir)/lib/ext2fs/ext2_err.h \ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \ - $(srcdir)/dqblk_v2.h + $(srcdir)/dqblk_v2.h $(top_srcdir)/lib/../e2fsck/dict.h quotaio_v2.o: $(srcdir)/quotaio_v2.c $(top_builddir)/lib/config.h \ - $(top_builddir)/lib/dirpaths.h $(srcdir)/common.h $(srcdir)/quotaio_v2.h \ - $(srcdir)/quota.h $(top_builddir)/lib/ext2fs/ext2_types.h \ - $(srcdir)/dqblk_v2.h $(srcdir)/quotaio_tree.h $(srcdir)/quotaio.h \ - $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \ - $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \ - $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \ - $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h + $(top_builddir)/lib/dirpaths.h $(srcdir)/common.h \ + $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/quotaio_v2.h \ + $(srcdir)/quotaio.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \ + $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \ + $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \ + $(top_builddir)/lib/ext2fs/ext2_err.h \ + $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \ + $(srcdir)/dqblk_v2.h $(srcdir)/quotaio_tree.h \ + $(top_srcdir)/lib/../e2fsck/dict.h dict.o: $(srcdir)/../../e2fsck/dict.c $(top_builddir)/lib/config.h \ $(top_builddir)/lib/dirpaths.h $(srcdir)/../../e2fsck/dict.h diff --git a/lib/quota/common.h b/lib/quota/common.h index b5e83316..f1ad79f2 100644 --- a/lib/quota/common.h +++ b/lib/quota/common.h @@ -7,20 +7,28 @@ #ifndef __QUOTA_COMMON_H__ #define __QUOTA_COMMON_H__ +#if EXT2_FLAT_INCLUDES +#include "e2_types.h" +#else +#include <ext2fs/ext2_types.h> +#endif /* EXT2_FLAT_INCLUDES */ + +/* #define DEBUG_QUOTA 1 */ + #ifndef __attribute__ # if !defined __GNUC__ || __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ # define __attribute__(x) # endif #endif -#define log_err(format, ...) fprintf(stderr, \ - "[ERROR] %s:%d:%s:: " format "\n", \ - __FILE__, __LINE__, __func__, __VA_ARGS__) +#define log_err(format, arg ...) \ + fprintf(stderr, "[ERROR] %s:%d:%s:: " format "\n", \ + __FILE__, __LINE__, __func__, ## arg) #ifdef DEBUG_QUOTA -# define log_debug(format, ...) fprintf(stderr, \ - "[DEBUG] %s:%d:%s:: " format "\n", \ - __FILE__, __LINE__, __func__, __VA_ARGS__) +# define log_debug(format, arg ...) \ + fprintf(stderr, "[DEBUG] %s:%d:%s:: " format "\n", \ + __FILE__, __LINE__, __func__, ## arg) #else # define log_debug(format, ...) #endif diff --git a/lib/quota/dqblk_v2.h b/lib/quota/dqblk_v2.h index 18055c69..d12512a6 100644 --- a/lib/quota/dqblk_v2.h +++ b/lib/quota/dqblk_v2.h @@ -7,28 +7,16 @@ #ifndef __QUOTA_DQBLK_V2_H__ #define __QUOTA_DQBLK_V2_H__ -#include <sys/types.h> #include "quotaio_tree.h" -#define Q_V2_GETQUOTA 0x0D00 /* Get limits and usage */ -#define Q_V2_SETQUOTA 0x0E00 /* Set limits and usage */ -#define Q_V2_SETUSE 0x0F00 /* Set only usage */ -#define Q_V2_SETQLIM 0x0700 /* Set only limits */ -#define Q_V2_GETINFO 0x0900 /* Get information about quota */ -#define Q_V2_SETINFO 0x0A00 /* Set information about quota */ -#define Q_V2_SETGRACE 0x0B00 /* Set just grace times in quotafile - * information */ -#define Q_V2_SETFLAGS 0x0C00 /* Set just flags in quotafile information */ -#define Q_V2_GETSTATS 0x1100 /* get collected stats (before proc was used) */ - /* Structure for format specific information */ struct v2_mem_dqinfo { struct qtree_mem_dqinfo dqi_qtree; - uint dqi_flags; /* Flags set in quotafile */ - uint dqi_used_entries; /* Number of entries in file - - updated by scan_dquots */ - uint dqi_data_blocks; /* Number of data blocks in file - - updated by scan_dquots */ + unsigned int dqi_flags; /* Flags set in quotafile */ + unsigned int dqi_used_entries; /* Number of entries in file - + updated by scan_dquots */ + unsigned int dqi_data_blocks; /* Number of data blocks in file - + updated by scan_dquots */ }; struct v2_mem_dqblk { diff --git a/lib/quota/mkquota.c b/lib/quota/mkquota.c index fbfde927..58803d04 100644 --- a/lib/quota/mkquota.c +++ b/lib/quota/mkquota.c @@ -15,17 +15,16 @@ #include "ext2fs/ext2fs.h" #include "e2p/e2p.h" -#include "quota.h" #include "quotaio.h" #include "quotaio_v2.h" #include "quotaio_tree.h" -#include "mkquota.h" #include "common.h" /* Needed for architectures where sizeof(int) != sizeof(void *) */ #define UINT_TO_VOIDPTR(val) ((void *)(intptr_t)(val)) #define VOIDPTR_TO_UINT(ptr) ((unsigned int)(intptr_t)(ptr)) +#if DEBUG_QUOTA static void print_inode(struct ext2_inode *inode) { if (!inode) @@ -46,17 +45,21 @@ static void print_inode(struct ext2_inode *inode) return; } -int quota_is_on(ext2_filsys fs, int type) +static void print_dquot(const char *desc, struct dquot *dq) { - char tmp[1024]; - qid_t id = (type == USRQUOTA) ? getuid() : getgid(); - -#ifdef HAVE_QUOTACTL - if (!quotactl(QCMD(Q_V2_GETQUOTA, type), fs->device_name, id, tmp)) - return 1; -#endif - return 0; + if (desc) + fprintf(stderr, "%s: ", desc); + fprintf(stderr, "%u %lld:%lld:%lld %lld:%lld:%lld\n", + dq->dq_id, dq->dq_dqb.dqb_curspace, + dq->dq_dqb.dqb_bsoftlimit, dq->dq_dqb.dqb_bhardlimit, + dq->dq_dqb.dqb_curinodes, + dq->dq_dqb.dqb_isoftlimit, dq->dq_dqb.dqb_ihardlimit); } +#else +static void print_dquot(const char *desc, struct dquot *dq) +{ +} +#endif /* * Returns 0 if not able to find the quota file, otherwise returns its @@ -71,7 +74,7 @@ int quota_file_exists(ext2_filsys fs, int qtype, int fmt) if (qtype >= MAXQUOTAS) return -EINVAL; - quota_get_qf_name(qtype, fmt, qf_name); + quota_get_qf_name(qtype, QFMT_VFS_V1, qf_name); ret = ext2fs_lookup(fs, EXT2_ROOT_INO, qf_name, strlen(qf_name), 0, &ino); @@ -100,8 +103,13 @@ void quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, int qtype) errcode_t quota_remove_inode(ext2_filsys fs, int qtype) { ext2_ino_t qf_ino; + errcode_t retval; - ext2fs_read_bitmaps(fs); + retval = ext2fs_read_bitmaps(fs); + if (retval) { + log_err("Couldn't read bitmaps: %s", error_message(retval)); + return retval; + } qf_ino = (qtype == USRQUOTA) ? fs->super->s_usr_quota_inum : fs->super->s_grp_quota_inum; quota_set_sb_inum(fs, 0, qtype); @@ -110,7 +118,12 @@ errcode_t quota_remove_inode(ext2_filsys fs, int qtype) quota_inode_truncate(fs, qf_ino); ext2fs_mark_super_dirty(fs); - ext2fs_write_bitmaps(fs); + fs->flags &= ~EXT2_FLAG_SUPER_ONLY; + retval = ext2fs_write_bitmaps(fs); + if (retval) { + log_err("Couldn't write bitmaps: %s", error_message(retval)); + return retval; + } return 0; } @@ -122,6 +135,7 @@ static void write_dquots(dict_t *dict, struct quota_handle *qh) for (n = dict_first(dict); n; n = dict_next(dict, n)) { dq = dnode_get(n); if (dq) { + print_dquot("write", dq); dq->dq_h = qh; update_grace_times(dq); qh->qh_ops->commit_dquot(dq); @@ -134,7 +148,7 @@ errcode_t quota_write_inode(quota_ctx_t qctx, int qtype) int retval = 0, i; dict_t *dict; ext2_filsys fs; - struct quota_handle *h; + struct quota_handle *h = NULL; int fmt = QFMT_VFS_V1; if (!qctx) @@ -143,11 +157,16 @@ errcode_t quota_write_inode(quota_ctx_t qctx, int qtype) fs = qctx->fs; retval = ext2fs_get_mem(sizeof(struct quota_handle), &h); if (retval) { - log_err("Unable to allocate quota handle", ""); + log_err("Unable to allocate quota handle: %s", + error_message(retval)); goto out; } - ext2fs_read_bitmaps(fs); + retval = ext2fs_read_bitmaps(fs); + if (retval) { + log_err("Couldn't read bitmaps: %s", error_message(retval)); + goto out; + } for (i = 0; i < MAXQUOTAS; i++) { if ((qtype != -1) && (i != qtype)) @@ -159,12 +178,12 @@ errcode_t quota_write_inode(quota_ctx_t qctx, int qtype) retval = quota_file_create(h, fs, i, fmt); if (retval < 0) { - log_err("Cannot initialize io on quotafile", ""); + log_err("Cannot initialize io on quotafile"); continue; } write_dquots(dict, h); - retval = quota_file_close(h); + retval = quota_file_close(qctx, h); if (retval < 0) { log_err("Cannot finish IO on new quotafile: %s", strerror(errno)); @@ -181,7 +200,11 @@ errcode_t quota_write_inode(quota_ctx_t qctx, int qtype) fs->flags &= ~EXT2_FLAG_SUPER_ONLY; } - ext2fs_write_bitmaps(fs); + retval = ext2fs_write_bitmaps(fs); + if (retval) { + log_err("Couldn't write bitmaps: %s", error_message(retval)); + goto out; + } out: if (h) ext2fs_free_mem(&h); @@ -199,7 +222,12 @@ static int dict_uint_cmp(const void *a, const void *b) c = VOIDPTR_TO_UINT(a); d = VOIDPTR_TO_UINT(b); - return c - d; + if (c == d) + return 0; + else if (c > d) + return 1; + else + return -1; } static inline qid_t get_qid(struct ext2_inode *inode, int qtype) @@ -223,23 +251,26 @@ static void quota_dnode_free(dnode_t *node, */ errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs, int qtype) { - int i, err = 0; + errcode_t err; dict_t *dict; quota_ctx_t ctx; + int i; err = ext2fs_get_mem(sizeof(struct quota_ctx), &ctx); if (err) { - log_err("Failed to allocate quota context", ""); + log_err("Failed to allocate quota context"); return err; } memset(ctx, 0, sizeof(struct quota_ctx)); for (i = 0; i < MAXQUOTAS; i++) { + ctx->quota_file[i] = NULL; if ((qtype != -1) && (i != qtype)) continue; err = ext2fs_get_mem(sizeof(dict_t), &dict); if (err) { - log_err("Failed to allocate dictionary", ""); + log_err("Failed to allocate dictionary"); + quota_release_context(&ctx); return err; } ctx->quota_dict[i] = dict; @@ -254,6 +285,7 @@ errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs, int qtype) void quota_release_context(quota_ctx_t *qctx) { + errcode_t err; dict_t *dict; int i; quota_ctx_t ctx; @@ -269,6 +301,14 @@ void quota_release_context(quota_ctx_t *qctx) dict_free_nodes(dict); free(dict); } + if (ctx->quota_file[i]) { + err = quota_file_close(ctx, ctx->quota_file[i]); + if (err) { + log_err("Cannot close quotafile: %s", + strerror(errno)); + ext2fs_free_mem(&ctx->quota_file[i]); + } + } } *qctx = NULL; free(ctx); @@ -284,7 +324,7 @@ static struct dquot *get_dq(dict_t *dict, __u32 key) dq = dnode_get(n); else { if (ext2fs_get_mem(sizeof(struct dquot), &dq)) { - log_err("Unable to allocate dquot", ""); + log_err("Unable to allocate dquot"); return NULL; } memset(dq, 0, sizeof(struct dquot)); @@ -399,7 +439,9 @@ errcode_t quota_compute_usage(quota_ctx_t qctx) } if (ino == 0) break; - if (inode.i_links_count) { + if (inode.i_links_count && + (ino == EXT2_ROOT_INO || + ino >= EXT2_FIRST_INODE(fs->super))) { space = ext2fs_inode_i_blocks(fs, &inode) << 9; quota_data_add(qctx, &inode, ino, space); quota_data_inodes(qctx, &inode, ino, +1); @@ -412,29 +454,49 @@ errcode_t quota_compute_usage(quota_ctx_t qctx) } struct scan_dquots_data { - quota_ctx_t qctx; - int limit_only; /* read limit only */ + dict_t *quota_dict; + int update_limits; /* update limits from disk */ + int update_usage; + int usage_is_inconsistent; }; static int scan_dquots_callback(struct dquot *dquot, void *cb_data) { - struct scan_dquots_data *scan_data = - (struct scan_dquots_data *)cb_data; - quota_ctx_t qctx = scan_data->qctx; + struct scan_dquots_data *scan_data = cb_data; + dict_t *quota_dict = scan_data->quota_dict; struct dquot *dq; - dq = get_dq(qctx->quota_dict[dquot->dq_h->qh_type], dquot->dq_id); - + dq = get_dq(quota_dict, dquot->dq_id); dq->dq_id = dquot->dq_id; - if (scan_data->limit_only) { - dq->dq_dqb.u.v2_mdqb.dqb_off = dquot->dq_dqb.u.v2_mdqb.dqb_off; + dq->dq_flags |= DQF_SEEN; + + print_dquot("mem", dq); + print_dquot("dsk", dquot); + + /* Check if there is inconsistancy. */ + if (dq->dq_dqb.dqb_curspace != dquot->dq_dqb.dqb_curspace || + dq->dq_dqb.dqb_curinodes != dquot->dq_dqb.dqb_curinodes) { + scan_data->usage_is_inconsistent = 1; + fprintf(stderr, "[QUOTA WARNING] Usage inconsistent for ID %d:" + "actual (%llu, %llu) != expected (%llu, %llu)\n", + dq->dq_id, (long long)dq->dq_dqb.dqb_curspace, + (long long)dq->dq_dqb.dqb_curinodes, + (long long)dquot->dq_dqb.dqb_curspace, + (long long)dquot->dq_dqb.dqb_curinodes); + } + + if (scan_data->update_limits) { dq->dq_dqb.dqb_ihardlimit = dquot->dq_dqb.dqb_ihardlimit; dq->dq_dqb.dqb_isoftlimit = dquot->dq_dqb.dqb_isoftlimit; dq->dq_dqb.dqb_bhardlimit = dquot->dq_dqb.dqb_bhardlimit; dq->dq_dqb.dqb_bsoftlimit = dquot->dq_dqb.dqb_bsoftlimit; - } else { - dq->dq_dqb = dquot->dq_dqb; } + + if (scan_data->update_usage) { + dq->dq_dqb.dqb_curspace = dquot->dq_dqb.dqb_curspace; + dq->dq_dqb.dqb_curinodes = dquot->dq_dqb.dqb_curinodes; + } + return 0; } @@ -442,12 +504,13 @@ static int scan_dquots_callback(struct dquot *dquot, void *cb_data) * Read all dquots from quota file into memory */ static errcode_t quota_read_all_dquots(struct quota_handle *qh, - quota_ctx_t qctx, int limit_only) + quota_ctx_t qctx, int update_limits) { struct scan_dquots_data scan_data; - scan_data.qctx = qctx; - scan_data.limit_only = limit_only; + scan_data.quota_dict = qctx->quota_dict[qh->qh_type]; + scan_data.update_limits = update_limits; + scan_data.update_usage = 0; return qh->qh_ops->scan_dquots(qh, scan_dquots_callback, &scan_data); } @@ -455,6 +518,7 @@ static errcode_t quota_read_all_dquots(struct quota_handle *qh, /* * Write all memory dquots into quota file */ +#if 0 /* currently unused, but may be useful in the future? */ static errcode_t quota_write_all_dquots(struct quota_handle *qh, quota_ctx_t qctx) { @@ -469,11 +533,12 @@ static errcode_t quota_write_all_dquots(struct quota_handle *qh, ext2fs_write_bitmaps(qctx->fs); return 0; } +#endif /* - * Update usage of in quota file, limits keep unchaged + * Updates the in-memory quota limits from the given quota inode. */ -errcode_t quota_update_inode(quota_ctx_t qctx, ext2_ino_t qf_ino, int type) +errcode_t quota_update_limits(quota_ctx_t qctx, ext2_ino_t qf_ino, int type) { struct quota_handle *qh; errcode_t err; @@ -483,20 +548,19 @@ errcode_t quota_update_inode(quota_ctx_t qctx, ext2_ino_t qf_ino, int type) err = ext2fs_get_mem(sizeof(struct quota_handle), &qh); if (err) { - log_err("Unable to allocate quota handle", ""); + log_err("Unable to allocate quota handle"); return err; } - err = quota_file_open(qh, qctx->fs, qf_ino, type, -1, EXT2_FILE_WRITE); + err = quota_file_open(qctx, qh, qf_ino, type, -1, 0); if (err) { - log_err("Open quota file failed", ""); + log_err("Open quota file failed"); goto out; } quota_read_all_dquots(qh, qctx, 1); - quota_write_all_dquots(qh, qctx); - err = quota_file_close(qh); + err = quota_file_close(qctx, qh); if (err) { log_err("Cannot finish IO on new quotafile: %s", strerror(errno)); @@ -507,3 +571,61 @@ out: ext2fs_free_mem(&qh); return err; } + +/* + * Compares the measured quota in qctx->quota_dict with that in the quota inode + * on disk and updates the limits in qctx->quota_dict. 'usage_inconsistent' is + * set to 1 if the supplied and on-disk quota usage values are not identical. + */ +errcode_t quota_compare_and_update(quota_ctx_t qctx, int qtype, + int *usage_inconsistent) +{ + ext2_filsys fs = qctx->fs; + struct quota_handle qh; + struct scan_dquots_data scan_data; + struct dquot *dq; + dnode_t *n; + dict_t *dict = qctx->quota_dict[qtype]; + errcode_t err = 0; + + if (!dict) + goto out; + + err = quota_file_open(qctx, &qh, 0, qtype, -1, 0); + if (err) { + log_err("Open quota file failed"); + goto out; + } + + scan_data.quota_dict = qctx->quota_dict[qtype]; + scan_data.update_limits = 1; + scan_data.update_usage = 0; + scan_data.usage_is_inconsistent = 0; + err = qh.qh_ops->scan_dquots(&qh, scan_dquots_callback, &scan_data); + if (err) { + log_err("Error scanning dquots"); + goto out_close_qh; + } + + for (n = dict_first(dict); n; n = dict_next(dict, n)) { + dq = dnode_get(n); + if (!dq) + continue; + if ((dq->dq_flags & DQF_SEEN) == 0) { + fprintf(stderr, "[QUOTA WARNING] " + "Missing quota entry ID %d\n", dq->dq_id); + scan_data.usage_is_inconsistent = 1; + } + } + *usage_inconsistent = scan_data.usage_is_inconsistent; + +out_close_qh: + err = quota_file_close(qctx, &qh); + if (err) { + log_err("Cannot close quotafile: %s", error_message(errno)); + if (qh.qh_qf.e2_file) + ext2fs_file_close(qh.qh_qf.e2_file); + } +out: + return err; +} diff --git a/lib/quota/mkquota.h b/lib/quota/mkquota.h deleted file mode 100644 index a5fa74ba..00000000 --- a/lib/quota/mkquota.h +++ /dev/null @@ -1,63 +0,0 @@ -/** mkquota.h - * - * Interface to the quota library. - * - * The quota library provides interface for creating and updating the quota - * files and the ext4 superblock fields. It supports the new VFS_V1 quota - * format. The quota library also provides support for keeping track of quotas - * in memory. - * The typical way to use the quota library is as follows: - * { - * quota_ctx_t qctx; - * - * quota_init_context(&qctx, fs, -1); - * { - * quota_compute_usage(qctx, -1); - * AND/OR - * quota_data_add/quota_data_sub/quota_data_inodes(); - * } - * quota_write_inode(qctx, USRQUOTA); - * quota_write_inode(qctx, GRPQUOTA); - * quota_release_context(&qctx); - * } - * - * This initial version does not support reading the quota files. This support - * will be added in near future. - * - * Aditya Kali <adityakali@google.com> - */ - -#ifndef __QUOTA_QUOTAIO_H__ -#define __QUOTA_QUOTAIO_H__ - -#include "ext2fs/ext2_fs.h" -#include "ext2fs/ext2fs.h" -#include "quota.h" -#include "../e2fsck/dict.h" - -typedef struct quota_ctx *quota_ctx_t; - -struct quota_ctx { - ext2_filsys fs; - dict_t *quota_dict[MAXQUOTAS]; -}; - -/* In mkquota.c */ -errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs, int qtype); -void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, - int adjust); -void quota_data_add(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, - qsize_t space); -void quota_data_sub(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, - qsize_t space); -errcode_t quota_write_inode(quota_ctx_t qctx, int qtype); -errcode_t quota_update_inode(quota_ctx_t qctx, ext2_ino_t qf_ino, int type); -errcode_t quota_compute_usage(quota_ctx_t qctx); -void quota_release_context(quota_ctx_t *qctx); - -errcode_t quota_remove_inode(ext2_filsys fs, int qtype); -int quota_is_on(ext2_filsys fs, int type); -int quota_file_exists(ext2_filsys fs, int qtype, int fmt); -void quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, int qtype); - -#endif /* __QUOTA_QUOTAIO_H__ */ diff --git a/lib/quota/quota.h b/lib/quota/quota.h deleted file mode 100644 index a943ec61..00000000 --- a/lib/quota/quota.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 1982, 1986 Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Robert Elz at The University of Melbourne. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _LINUX_QUOTA_ -#define _LINUX_QUOTA_ - -#include <errno.h> -#include <sys/types.h> -#include <ext2fs/ext2_types.h> - -#define __DQUOT_VERSION__ "dquot_6.5.2" - -typedef u_int32_t qid_t; /* Type in which we store ids in memory */ -typedef int64_t qsize_t; /* Type in which we store size limitations */ - -#define MAXQUOTAS 2 -#define USRQUOTA 0 /* element used for user quotas */ -#define GRPQUOTA 1 /* element used for group quotas */ - -/* - * Definitions for the default names of the quotas files. - */ -#define INITQFNAMES { \ - "user", /* USRQUOTA */ \ - "group", /* GRPQUOTA */ \ - "undefined", \ -}; - -/* - * Definitions of magics and versions of current quota files - */ -#define INITQMAGICS {\ - 0xd9c01f11, /* USRQUOTA */\ - 0xd9c01927 /* GRPQUOTA */\ -} - -/* Size of blocks in which are counted size limits in generic utility parts */ -#define QUOTABLOCK_BITS 10 -#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) - -/* Conversion routines from and to quota blocks */ -#define qb2kb(x) ((x) << (QUOTABLOCK_BITS-10)) -#define kb2qb(x) ((x) >> (QUOTABLOCK_BITS-10)) -#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS) - -/* - * Command definitions for the 'quotactl' system call. - * The commands are broken into a main command defined below - * and a subcommand that is used to convey the type of - * quota that is being manipulated (see above). - */ -#define SUBCMDMASK 0x00ff -#define SUBCMDSHIFT 8 -#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK)) - -#define Q_SYNC 0x800001 /* sync disk copy of a filesystems quotas */ -#define Q_QUOTAON 0x800002 /* turn quotas on */ -#define Q_QUOTAOFF 0x800003 /* turn quotas off */ -#define Q_GETFMT 0x800004 /* get quota format used on given filesystem */ -#define Q_GETINFO 0x800005 /* get information about quota files */ -#define Q_SETINFO 0x800006 /* set information about quota files */ -#define Q_GETQUOTA 0x800007 /* get user quota structure */ -#define Q_SETQUOTA 0x800008 /* set user quota structure */ - -/* Quota format type IDs */ -#define QFMT_VFS_OLD 1 -#define QFMT_VFS_V0 2 -#define QFMT_OCFS2 3 -#define QFMT_VFS_V1 4 - -/* Size of block in which space limits are passed through the quota - * interface */ -#define QIF_DQBLKSIZE_BITS 10 -#define QIF_DQBLKSIZE (1 << QIF_DQBLKSIZE_BITS) - -/* - * Structure used for setting quota information about file via quotactl - * Following flags are used to specify which fields are valid - */ -#define IIF_BGRACE 1 -#define IIF_IGRACE 2 -#define IIF_FLAGS 4 -#define IIF_ALL (IIF_BGRACE | IIF_IGRACE | IIF_FLAGS) - -struct if_dqinfo { - __u64 dqi_bgrace; - __u64 dqi_igrace; - __u32 dqi_flags; - __u32 dqi_valid; -}; - -/* - * Definitions for quota netlink interface - */ -#define QUOTA_NL_NOWARN 0 -#define QUOTA_NL_IHARDWARN 1 /* Inode hardlimit reached */ -#define QUOTA_NL_ISOFTLONGWARN 2 /* Inode grace time expired */ -#define QUOTA_NL_ISOFTWARN 3 /* Inode softlimit reached */ -#define QUOTA_NL_BHARDWARN 4 /* Block hardlimit reached */ -#define QUOTA_NL_BSOFTLONGWARN 5 /* Block grace time expired */ -#define QUOTA_NL_BSOFTWARN 6 /* Block softlimit reached */ -#define QUOTA_NL_IHARDBELOW 7 /* Usage got below inode hardlimit */ -#define QUOTA_NL_ISOFTBELOW 8 /* Usage got below inode softlimit */ -#define QUOTA_NL_BHARDBELOW 9 /* Usage got below block hardlimit */ -#define QUOTA_NL_BSOFTBELOW 10 /* Usage got below block softlimit */ - -enum { - QUOTA_NL_C_UNSPEC, - QUOTA_NL_C_WARNING, - __QUOTA_NL_C_MAX, -}; -#define QUOTA_NL_C_MAX (__QUOTA_NL_C_MAX - 1) - -enum { - QUOTA_NL_A_UNSPEC, - QUOTA_NL_A_QTYPE, - QUOTA_NL_A_EXCESS_ID, - QUOTA_NL_A_WARNING, - QUOTA_NL_A_DEV_MAJOR, - QUOTA_NL_A_DEV_MINOR, - QUOTA_NL_A_CAUSED_ID, - __QUOTA_NL_A_MAX, -}; -#define QUOTA_NL_A_MAX (__QUOTA_NL_A_MAX - 1) - -#endif /* _QUOTA_ */ diff --git a/lib/quota/quota.pc.in b/lib/quota/quota.pc.in deleted file mode 100644 index bcc3c441..00000000 --- a/lib/quota/quota.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: quota -Description: Quota management library -Version: @E2FSPROGS_VERSION@ -Requires: -Cflags: -I${includedir}/quota -Libs: -L${libdir} -lquota diff --git a/lib/quota/quotaio.c b/lib/quota/quotaio.c index 481d5f57..65fccaa9 100644 --- a/lib/quota/quotaio.c +++ b/lib/quota/quotaio.c @@ -11,6 +11,7 @@ #include <string.h> #include <unistd.h> #include <stdlib.h> +#include <time.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/file.h> @@ -18,7 +19,7 @@ #include "common.h" #include "quotaio.h" -static const char extensions[MAXQUOTAS + 2][20] = INITQFNAMES; +static const char * const extensions[MAXQUOTAS] = {"user", "group"}; static const char * const basenames[] = { "", /* undefined */ "quota", /* QFMT_VFS_OLD */ @@ -27,18 +28,10 @@ static const char * const basenames[] = { "aquota" /* QFMT_VFS_V1 */ }; -static const char * const fmtnames[] = { - "vfsold", - "vfsv0", - "vfsv1", - "rpc", - "xfs" -}; - /* Header in all newer quotafiles */ struct disk_dqheader { - u_int32_t dqh_magic; - u_int32_t dqh_version; + __u32 dqh_magic; + __u32 dqh_version; } __attribute__ ((packed)); /** @@ -65,7 +58,6 @@ const char *quota_get_qf_name(int type, int fmt, char *buf) const char *quota_get_qf_path(const char *mntpt, int qtype, int fmt, char *path_buf, size_t path_buf_size) { - struct stat qf_stat; char qf_name[QUOTA_NAME_LEN]; if (!mntpt || !path_buf || !path_buf_size) @@ -106,26 +98,12 @@ void update_grace_times(struct dquot *q) } } -static int release_blocks_proc(ext2_filsys fs, blk64_t *blocknr, - e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), - blk64_t ref_block EXT2FS_ATTR((unused)), - int ref_offset EXT2FS_ATTR((unused)), - void *private EXT2FS_ATTR((unused))) -{ - blk64_t block; - - block = *blocknr; - ext2fs_block_alloc_stats2(fs, block, -1); - return 0; -} - static int compute_num_blocks_proc(ext2_filsys fs, blk64_t *blocknr, e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), blk64_t ref_block EXT2FS_ATTR((unused)), int ref_offset EXT2FS_ATTR((unused)), void *private) { - blk64_t block; blk64_t *num_blocks = private; *num_blocks += 1; @@ -136,19 +114,22 @@ errcode_t quota_inode_truncate(ext2_filsys fs, ext2_ino_t ino) { struct ext2_inode inode; errcode_t err; - int i; if ((err = ext2fs_read_inode(fs, ino, &inode))) return err; - inode.i_dtime = fs->now ? fs->now : time(0); - if (!ext2fs_inode_has_valid_blocks2(fs, &inode)) - return 0; - - ext2fs_block_iterate3(fs, ino, BLOCK_FLAG_READ_ONLY, NULL, - release_blocks_proc, NULL); - - memset(&inode, 0, sizeof(struct ext2_inode)); + if ((ino == EXT4_USR_QUOTA_INO) || (ino == EXT4_GRP_QUOTA_INO)) { + inode.i_dtime = fs->now ? fs->now : time(0); + if (!ext2fs_inode_has_valid_blocks2(fs, &inode)) + return 0; + err = ext2fs_punch(fs, ino, &inode, NULL, 0, ~0ULL); + if (err) + return err; + fs->flags &= ~EXT2_FLAG_SUPER_ONLY; + memset(&inode, 0, sizeof(struct ext2_inode)); + } else { + inode.i_flags &= ~EXT2_IMMUTABLE_FL; + } err = ext2fs_write_inode(fs, ino, &inode); return err; } @@ -216,11 +197,16 @@ static unsigned int quota_read_nomount(struct quota_file *qf, /* * Detect quota format and initialize quota IO */ -errcode_t quota_file_open(struct quota_handle *h, ext2_filsys fs, +errcode_t quota_file_open(quota_ctx_t qctx, struct quota_handle *h, ext2_ino_t qf_ino, int type, int fmt, int flags) { + ext2_filsys fs = qctx->fs; ext2_file_t e2_file; errcode_t err; + int allocated_handle = 0; + + if (type >= MAXQUOTAS) + return EINVAL; if (fmt == -1) fmt = QFMT_VFS_V1; @@ -229,18 +215,42 @@ errcode_t quota_file_open(struct quota_handle *h, ext2_filsys fs, if (err) return err; + if (qf_ino == 0) { + if (type == USRQUOTA) + qf_ino = fs->super->s_usr_quota_inum; + else + qf_ino = fs->super->s_grp_quota_inum; + } + log_debug("Opening quota ino=%lu, type=%d", qf_ino, type); err = ext2fs_file_open(fs, qf_ino, flags, &e2_file); if (err) { log_err("ext2fs_file_open failed: %s", error_message(err)); return err; } - h->qh_qf.e2_file = e2_file; + if (!h) { + if (qctx->quota_file[type]) { + h = qctx->quota_file[type]; + if (((flags & EXT2_FILE_WRITE) == 0) || + (h->qh_file_flags & EXT2_FILE_WRITE)) + return 0; + (void) quota_file_close(qctx, h); + } + err = ext2fs_get_mem(sizeof(struct quota_handle), &h); + if (err) { + log_err("Unable to allocate quota handle"); + return err; + } + allocated_handle = 1; + } + + h->qh_qf.e2_file = e2_file; h->qh_qf.fs = fs; h->qh_qf.ino = qf_ino; h->e2fs_write = quota_write_nomount; h->e2fs_read = quota_read_nomount; + h->qh_file_flags = flags; h->qh_io_flags = 0; h->qh_type = type; h->qh_fmt = fmt; @@ -249,18 +259,23 @@ errcode_t quota_file_open(struct quota_handle *h, ext2_filsys fs, if (h->qh_ops->check_file && (h->qh_ops->check_file(h, type, fmt) == 0)) { - log_err("qh_ops->check_file failed", ""); - ext2fs_file_close(e2_file); - return -1; + log_err("qh_ops->check_file failed"); + goto errout; } if (h->qh_ops->init_io && (h->qh_ops->init_io(h) < 0)) { - log_err("qh_ops->init_io failed", ""); - ext2fs_file_close(e2_file); - return -1; + log_err("qh_ops->init_io failed"); + goto errout; } + if (allocated_handle) + qctx->quota_file[type] = h; return 0; +errout: + ext2fs_file_close(e2_file); + if (allocated_handle) + ext2fs_free_mem(&h); + return -1; } static errcode_t quota_inode_init_new(ext2_filsys fs, ext2_ino_t ino) @@ -270,7 +285,7 @@ static errcode_t quota_inode_init_new(ext2_filsys fs, ext2_ino_t ino) err = ext2fs_read_inode(fs, ino, &inode); if (err) { - log_err("ex2fs_read_inode failed", ""); + log_err("ex2fs_read_inode failed"); return err; } @@ -322,16 +337,16 @@ errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs, int type, in err = quota_inode_init_new(fs, qf_inum); if (err) { - log_err("init_new_quota_inode failed", ""); + log_err("init_new_quota_inode failed"); goto out_err; } h->qh_qf.ino = qf_inum; + h->qh_file_flags = EXT2_FILE_WRITE | EXT2_FILE_CREATE; h->e2fs_write = quota_write_nomount; h->e2fs_read = quota_read_nomount; log_debug("Creating quota ino=%lu, type=%d", qf_inum, type); - err = ext2fs_file_open(fs, qf_inum, - EXT2_FILE_WRITE | EXT2_FILE_CREATE, &e2_file); + err = ext2fs_file_open(fs, qf_inum, h->qh_file_flags, &e2_file); if (err) { log_err("ext2fs_file_open failed: %d", err); goto out_err; @@ -345,7 +360,7 @@ errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs, int type, in h->qh_ops = "afile_ops_2; if (h->qh_ops->new_io && (h->qh_ops->new_io(h) < 0)) { - log_err("qh_ops->new_io failed", ""); + log_err("qh_ops->new_io failed"); goto out_err1; } @@ -364,7 +379,7 @@ out_err: /* * Close quotafile and release handle */ -errcode_t quota_file_close(struct quota_handle *h) +errcode_t quota_file_close(quota_ctx_t qctx, struct quota_handle *h) { if (h->qh_io_flags & IOFL_INFODIRTY) { if (h->qh_ops->write_info && h->qh_ops->write_info(h) < 0) @@ -375,12 +390,18 @@ errcode_t quota_file_close(struct quota_handle *h) if (h->qh_ops->end_io && h->qh_ops->end_io(h) < 0) return -1; if (h->qh_qf.e2_file) { + __u64 new_size, size; + + new_size = compute_inode_size(h->qh_qf.fs, h->qh_qf.ino); ext2fs_file_flush(h->qh_qf.e2_file); - ext2fs_file_set_size2(h->qh_qf.e2_file, - compute_inode_size(h->qh_qf.fs, h->qh_qf.ino)); + if (ext2fs_file_get_lsize(h->qh_qf.e2_file, &size)) + new_size = 0; + if (size != new_size) + ext2fs_file_set_size2(h->qh_qf.e2_file, new_size); ext2fs_file_close(h->qh_qf.e2_file); } - + if (qctx->quota_file[h->qh_type] == h) + ext2fs_free_mem(&qctx->quota_file[h->qh_type]); return 0; } @@ -392,7 +413,7 @@ struct dquot *get_empty_dquot(void) struct dquot *dquot; if (ext2fs_get_memzero(sizeof(struct dquot), &dquot)) { - log_err("Failed to allocate dquot", ""); + log_err("Failed to allocate dquot"); return NULL; } diff --git a/lib/quota/quotaio.h b/lib/quota/quotaio.h index 91a1ff27..7ca7830e 100644 --- a/lib/quota/quotaio.h +++ b/lib/quota/quotaio.h @@ -1,6 +1,32 @@ /** quotaio.h * + * Interface to the quota library. + * + * The quota library provides interface for creating and updating the quota + * files and the ext4 superblock fields. It supports the new VFS_V1 quota + * format. The quota library also provides support for keeping track of quotas + * in memory. + * The typical way to use the quota library is as follows: + * { + * quota_ctx_t qctx; + * + * quota_init_context(&qctx, fs, -1); + * { + * quota_compute_usage(qctx, -1); + * AND/OR + * quota_data_add/quota_data_sub/quota_data_inodes(); + * } + * quota_write_inode(qctx, USRQUOTA); + * quota_write_inode(qctx, GRPQUOTA); + * quota_release_context(&qctx); + * } + * + * This initial version does not support reading the quota files. This support + * will be added in near future. + * + * Aditya Kali <adityakali@google.com> * Header of IO operations for quota utilities + * * Jan Kara <jack@suse.cz> */ @@ -11,14 +37,44 @@ #include <sys/types.h> #include <sys/stat.h> +#include "ext2fs/ext2_fs.h" #include "ext2fs/ext2fs.h" -#include "quota.h" #include "dqblk_v2.h" +#include "../e2fsck/dict.h" + +typedef int64_t qsize_t; /* Type in which we store size limitations */ + +#define MAXQUOTAS 2 +#define USRQUOTA 0 +#define GRPQUOTA 1 + +typedef struct quota_ctx *quota_ctx_t; + +struct quota_ctx { + ext2_filsys fs; + dict_t *quota_dict[MAXQUOTAS]; + struct quota_handle *quota_file[MAXQUOTAS]; +}; + +/* + * Definitions of magics and versions of current quota files + */ +#define INITQMAGICS {\ + 0xd9c01f11, /* USRQUOTA */\ + 0xd9c01927 /* GRPQUOTA */\ +} + +/* Size of blocks in which are counted size limits in generic utility parts */ +#define QUOTABLOCK_BITS 10 +#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) +#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS) + +/* Quota format type IDs */ +#define QFMT_VFS_OLD 1 +#define QFMT_VFS_V0 2 +#define QFMT_VFS_V1 4 /* - * Definitions for disk quotas imposed on the average user - * (big brother finally hits Linux). - * * The following constants define the default amount of time given a user * before the soft limits are treated as hard limits (usually resulting * in an allocation failure). The timer is started when the user crosses @@ -27,11 +83,7 @@ #define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ #define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ -#define IOFL_QUOTAON 0x01 /* Is quota enabled in kernel? */ -#define IOFL_INFODIRTY 0x02 /* Did info change? */ -#define IOFL_RO 0x04 /* Just RO access? */ -#define IOFL_NFS_MIXED_PATHS 0x08 /* Should we trim leading slashes - from NFSv4 mountpoints? */ +#define IOFL_INFODIRTY 0x01 /* Did info change? */ struct quotafile_ops; @@ -54,6 +106,7 @@ struct quota_file { struct quota_handle { int qh_type; /* Type of quotafile */ int qh_fmt; /* Quotafile format */ + int qh_file_flags; int qh_io_flags; /* IO flags for file */ struct quota_file qh_qf; unsigned int (*e2fs_read)(struct quota_file *qf, ext2_loff_t offset, @@ -64,19 +117,6 @@ struct quota_handle { struct util_dqinfo qh_info; /* Generic quotafile info */ }; -/* Statistics gathered from kernel */ -struct util_dqstats { - u_int32_t lookups; - u_int32_t drops; - u_int32_t reads; - u_int32_t writes; - u_int32_t cache_hits; - u_int32_t allocated_dquots; - u_int32_t free_dquots; - u_int32_t syncs; - u_int32_t version; -}; - /* Utility quota block */ struct util_dqblk { qsize_t dqb_ihardlimit; @@ -101,6 +141,8 @@ struct dquot { struct util_dqblk dq_dqb; /* Parsed data of dquot */ }; +#define DQF_SEEN 0x0001 + /* Structure of quotafile operations */ struct quotafile_ops { /* Check whether quotafile is in our format */ @@ -129,17 +171,9 @@ struct quotafile_ops { /* This might go into a special header file but that sounds a bit silly... */ extern struct quotafile_ops quotafile_ops_meta; -static inline void mark_quotafile_info_dirty(struct quota_handle *h) -{ - h->qh_io_flags |= IOFL_INFODIRTY; -} - -#define QIO_ENABLED(h) ((h)->qh_io_flags & IOFL_QUOTAON) -#define QIO_RO(h) ((h)->qh_io_flags & IOFL_RO) - /* Open existing quotafile of given type (and verify its format) on given * filesystem. */ -errcode_t quota_file_open(struct quota_handle *h, ext2_filsys fs, +errcode_t quota_file_open(quota_ctx_t qctx, struct quota_handle *h, ext2_ino_t qf_ino, int type, int fmt, int flags); @@ -148,7 +182,7 @@ errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs, int type, int fmt); /* Close quotafile */ -errcode_t quota_file_close(struct quota_handle *h); +errcode_t quota_file_close(quota_ctx_t qctx, struct quota_handle *h); /* Get empty quota structure */ struct dquot *get_empty_dquot(void); @@ -167,4 +201,25 @@ const char *quota_get_qf_name(int type, int fmt, char *buf); const char *quota_get_qf_path(const char *mntpt, int qtype, int fmt, char *path_buf, size_t path_buf_size); +/* In mkquota.c */ +errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs, int qtype); +void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, + int adjust); +void quota_data_add(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, + qsize_t space); +void quota_data_sub(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, + qsize_t space); +errcode_t quota_write_inode(quota_ctx_t qctx, int qtype); +errcode_t quota_update_limits(quota_ctx_t qctx, ext2_ino_t qf_ino, int type); +errcode_t quota_compute_usage(quota_ctx_t qctx); +void quota_release_context(quota_ctx_t *qctx); + +errcode_t quota_remove_inode(ext2_filsys fs, int qtype); +int quota_file_exists(ext2_filsys fs, int qtype, int fmt); +void quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, int qtype); +errcode_t quota_compare_and_update(quota_ctx_t qctx, int qtype, + int *usage_inconsistent); + + + #endif /* GUARD_QUOTAIO_H */ diff --git a/lib/quota/quotaio_tree.c b/lib/quota/quotaio_tree.c index 9080e77f..4d7a9ab1 100644 --- a/lib/quota/quotaio_tree.c +++ b/lib/quota/quotaio_tree.c @@ -24,7 +24,7 @@ static inline dqbuf_t getdqbuf(void) { dqbuf_t buf; if (ext2fs_get_memzero(QT_BLKSIZE, &buf)) { - log_err("Failed to allocate dqbuf", ""); + log_err("Failed to allocate dqbuf"); return NULL; } @@ -53,8 +53,13 @@ static int get_index(qid_t id, int depth) return (id >> ((QT_TREEDEPTH - depth - 1) * 8)) & 0xff; } +static inline void mark_quotafile_info_dirty(struct quota_handle *h) +{ + h->qh_io_flags |= IOFL_INFODIRTY; +} + /* Read given block */ -static void read_blk(struct quota_handle *h, uint blk, dqbuf_t buf) +static void read_blk(struct quota_handle *h, unsigned int blk, dqbuf_t buf) { int err; @@ -67,7 +72,7 @@ static void read_blk(struct quota_handle *h, uint blk, dqbuf_t buf) } /* Write block */ -static int write_blk(struct quota_handle *h, uint blk, dqbuf_t buf) +static int write_blk(struct quota_handle *h, unsigned int blk, dqbuf_t buf) { int err; @@ -101,7 +106,7 @@ static int get_free_dqblk(struct quota_handle *h) if (write_blk(h, info->dqi_blocks, buf) < 0) { freedqbuf(buf); log_err("Cannot allocate new quota block " - "(out of disk space).", ""); + "(out of disk space)."); return -ENOSPC; } blk = info->dqi_blocks++; @@ -112,7 +117,8 @@ static int get_free_dqblk(struct quota_handle *h) } /* Put given block to free list */ -static void put_free_dqblk(struct quota_handle *h, dqbuf_t buf, uint blk) +static void put_free_dqblk(struct quota_handle *h, dqbuf_t buf, + unsigned int blk) { struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; @@ -126,11 +132,12 @@ static void put_free_dqblk(struct quota_handle *h, dqbuf_t buf, uint blk) } /* Remove given block from the list of blocks with free entries */ -static void remove_free_dqentry(struct quota_handle *h, dqbuf_t buf, uint blk) +static void remove_free_dqentry(struct quota_handle *h, dqbuf_t buf, + unsigned int blk) { dqbuf_t tmpbuf = getdqbuf(); struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; - uint nextblk = ext2fs_le32_to_cpu(dh->dqdh_next_free), prevblk = + unsigned int nextblk = ext2fs_le32_to_cpu(dh->dqdh_next_free), prevblk = ext2fs_le32_to_cpu(dh->dqdh_prev_free); @@ -159,7 +166,8 @@ static void remove_free_dqentry(struct quota_handle *h, dqbuf_t buf, uint blk) } /* Insert given block to the beginning of list with free entries */ -static void insert_free_dqentry(struct quota_handle *h, dqbuf_t buf, uint blk) +static void insert_free_dqentry(struct quota_handle *h, dqbuf_t buf, + unsigned int blk) { dqbuf_t tmpbuf = getdqbuf(); struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; @@ -183,8 +191,8 @@ static void insert_free_dqentry(struct quota_handle *h, dqbuf_t buf, uint blk) } /* Find space for dquot */ -static uint find_free_dqentry(struct quota_handle *h, struct dquot *dquot, - int *err) +static unsigned int find_free_dqentry(struct quota_handle *h, + struct dquot *dquot, int *err) { int blk, i; struct qt_disk_dqdbheader *dh; @@ -230,8 +238,7 @@ static uint find_free_dqentry(struct quota_handle *h, struct dquot *dquot, ddquot += info->dqi_entry_size; if (i == qtree_dqstr_in_blk(info)) - log_err("find_free_dqentry(): Data block full but it " - "shouldn't.", ""); + log_err("find_free_dqentry(): Data block full unexpectedly."); write_blk(h, blk, buf); dquot->dq_dqb.u.v2_mdqb.dqb_off = @@ -243,12 +250,12 @@ static uint find_free_dqentry(struct quota_handle *h, struct dquot *dquot, /* Insert reference to structure into the trie */ static int do_insert_tree(struct quota_handle *h, struct dquot *dquot, - uint * treeblk, int depth) + unsigned int * treeblk, int depth) { dqbuf_t buf; int newson = 0, newact = 0; - u_int32_t *ref; - uint newblk; + __u32 *ref; + unsigned int newblk; int ret = 0; log_debug("inserting in tree: treeblk=%u, depth=%d", *treeblk, depth); @@ -267,7 +274,7 @@ static int do_insert_tree(struct quota_handle *h, struct dquot *dquot, read_blk(h, *treeblk, buf); } - ref = (u_int32_t *) buf; + ref = (__u32 *) buf; newblk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); if (!newblk) newson = 1; @@ -297,11 +304,11 @@ out_buf: /* Wrapper for inserting quota structure into tree */ static void dq_insert_tree(struct quota_handle *h, struct dquot *dquot) { - uint tmp = QT_TREEOFF; + unsigned int tmp = QT_TREEOFF; if (do_insert_tree(h, dquot, &tmp, 0) < 0) log_err("Cannot write quota (id %u): %s", - (uint) dquot->dq_id, strerror(errno)); + (unsigned int) dquot->dq_id, strerror(errno)); } /* Write dquot to file */ @@ -319,9 +326,10 @@ void qtree_write_dquot(struct dquot *dquot) if (ret) { errno = ENOMEM; log_err("Quota write failed (id %u): %s", - (uint)dquot->dq_id, strerror(errno)); + (unsigned int)dquot->dq_id, strerror(errno)); return; } + memset(ddquot, 0, info->dqi_entry_size); if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) dq_insert_tree(dquot->dq_h, dquot); @@ -336,13 +344,14 @@ void qtree_write_dquot(struct dquot *dquot) if (ret > 0) errno = ENOSPC; log_err("Quota write failed (id %u): %s", - (uint)dquot->dq_id, strerror(errno)); + (unsigned int)dquot->dq_id, strerror(errno)); } ext2fs_free_mem(&ddquot); } /* Free dquot entry in data block */ -static void free_dqentry(struct quota_handle *h, struct dquot *dquot, uint blk) +static void free_dqentry(struct quota_handle *h, struct dquot *dquot, + unsigned int blk) { struct qt_disk_dqdbheader *dh; struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; @@ -354,7 +363,7 @@ static void free_dqentry(struct quota_handle *h, struct dquot *dquot, uint blk) if (dquot->dq_dqb.u.v2_mdqb.dqb_off >> QT_BLKSIZE_BITS != blk) log_err("Quota structure has offset to other block (%u) " "than it should (%u).", blk, - (uint) (dquot->dq_dqb.u.v2_mdqb.dqb_off >> + (unsigned int) (dquot->dq_dqb.u.v2_mdqb.dqb_off >> QT_BLKSIZE_BITS)); read_blk(h, blk, buf); @@ -384,11 +393,11 @@ static void free_dqentry(struct quota_handle *h, struct dquot *dquot, uint blk) /* Remove reference to dquot from tree */ static void remove_tree(struct quota_handle *h, struct dquot *dquot, - uint * blk, int depth) + unsigned int * blk, int depth) { dqbuf_t buf = getdqbuf(); - uint newblk; - u_int32_t *ref = (u_int32_t *) buf; + unsigned int newblk; + __u32 *ref = (__u32 *) buf; if (!buf) return; @@ -424,7 +433,7 @@ static void remove_tree(struct quota_handle *h, struct dquot *dquot, /* Delete dquot from tree */ void qtree_delete_dquot(struct dquot *dquot) { - uint tmp = QT_TREEOFF; + unsigned int tmp = QT_TREEOFF; if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) /* Even not allocated? */ return; @@ -433,7 +442,7 @@ void qtree_delete_dquot(struct dquot *dquot) /* Find entry in block */ static ext2_loff_t find_block_dqentry(struct quota_handle *h, - struct dquot *dquot, uint blk) + struct dquot *dquot, unsigned int blk) { struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; dqbuf_t buf = getdqbuf(); @@ -460,11 +469,11 @@ static ext2_loff_t find_block_dqentry(struct quota_handle *h, /* Find entry for given id in the tree */ static ext2_loff_t find_tree_dqentry(struct quota_handle *h, struct dquot *dquot, - uint blk, int depth) + unsigned int blk, int depth) { dqbuf_t buf = getdqbuf(); ext2_loff_t ret = 0; - u_int32_t *ref = (u_int32_t *) buf; + __u32 *ref = (__u32 *) buf; if (!buf) return -ENOMEM; @@ -536,7 +545,7 @@ struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id) #define set_bit(bmp, ind) ((bmp)[(ind) >> 3] |= (1 << ((ind) & 7))) #define get_bit(bmp, ind) ((bmp)[(ind) >> 3] & (1 << ((ind) & 7))) -static int report_block(struct dquot *dquot, uint blk, char *bitmap, +static int report_block(struct dquot *dquot, unsigned int blk, char *bitmap, int (*process_dquot) (struct dquot *, void *), void *data) { @@ -570,7 +579,7 @@ static int report_block(struct dquot *dquot, uint blk, char *bitmap, return entries; } -static void check_reference(struct quota_handle *h, uint blk) +static void check_reference(struct quota_handle *h, unsigned int blk) { if (blk >= h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks) log_err("Illegal reference (%u >= %u) in %s quota file. " @@ -581,13 +590,14 @@ static void check_reference(struct quota_handle *h, uint blk) type2name(h->qh_type)); } -static int report_tree(struct dquot *dquot, uint blk, int depth, char *bitmap, +static int report_tree(struct dquot *dquot, unsigned int blk, int depth, + char *bitmap, int (*process_dquot) (struct dquot *, void *), void *data) { int entries = 0, i; dqbuf_t buf = getdqbuf(); - u_int32_t *ref = (u_int32_t *) buf; + __u32 *ref = (__u32 *) buf; if (!buf) return 0; @@ -616,9 +626,9 @@ static int report_tree(struct dquot *dquot, uint blk, int depth, char *bitmap, return entries; } -static uint find_set_bits(char *bmp, int blocks) +static unsigned int find_set_bits(char *bmp, int blocks) { - uint i, used = 0; + unsigned int i, used = 0; for (i = 0; i < blocks; i++) if (get_bit(bmp, i)) diff --git a/lib/quota/quotaio_tree.h b/lib/quota/quotaio_tree.h index 37c15cef..be34edbc 100644 --- a/lib/quota/quotaio_tree.h +++ b/lib/quota/quotaio_tree.h @@ -6,7 +6,8 @@ #define _LINUX_QUOTA_TREE_H #include <sys/types.h> -#include "quota.h" + +typedef __u32 qid_t; /* Type in which we store ids in memory */ #define QT_TREEOFF 1 /* Offset of tree in file in blocks */ #define QT_TREEDEPTH 4 /* Depth of quota tree */ @@ -19,13 +20,13 @@ * so there will be space for exactly 21 quota-entries in a block */ struct qt_disk_dqdbheader { - u_int32_t dqdh_next_free; /* Number of next block with free + __u32 dqdh_next_free; /* Number of next block with free * entry */ - u_int32_t dqdh_prev_free; /* Number of previous block with free + __u32 dqdh_prev_free; /* Number of previous block with free * entry */ - u_int16_t dqdh_entries; /* Number of valid entries in block */ - u_int16_t dqdh_pad1; - u_int32_t dqdh_pad2; + __u16 dqdh_entries; /* Number of valid entries in block */ + __u16 dqdh_pad1; + __u32 dqdh_pad2; } __attribute__ ((packed)); struct dquot; diff --git a/lib/quota/quotaio_v2.c b/lib/quota/quotaio_v2.c index e6587068..e7bf29c3 100644 --- a/lib/quota/quotaio_v2.c +++ b/lib/quota/quotaio_v2.c @@ -18,8 +18,6 @@ #include "quotaio.h" #include "quotaio_tree.h" -typedef char *dqbuf_t; - static int v2_check_file(struct quota_handle *h, int type, int fmt); static int v2_init_io(struct quota_handle *h); static int v2_new_io(struct quota_handle *h); @@ -43,9 +41,6 @@ struct quotafile_ops quotafile_ops_2 = { .report = v2_report, }; -#define getdqbuf() smalloc(V2_DQBLKSIZE) -#define freedqbuf(buf) free(buf) - /* * Copy dquot from disk to memory */ @@ -140,34 +135,6 @@ static inline void v2_mem2diskdqinfo(struct v2_disk_dqinfo *d, ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_entry); } -/* Convert kernel quotablock format to utility one */ -static inline void v2_kern2utildqblk(struct util_dqblk *u, - struct v2_kern_dqblk *k) -{ - u->dqb_ihardlimit = k->dqb_ihardlimit; - u->dqb_isoftlimit = k->dqb_isoftlimit; - u->dqb_bhardlimit = k->dqb_bhardlimit; - u->dqb_bsoftlimit = k->dqb_bsoftlimit; - u->dqb_curinodes = k->dqb_curinodes; - u->dqb_curspace = k->dqb_curspace; - u->dqb_itime = k->dqb_itime; - u->dqb_btime = k->dqb_btime; -} - -/* Convert utility quotablock format to kernel one */ -static inline void v2_util2kerndqblk(struct v2_kern_dqblk *k, - struct util_dqblk *u) -{ - k->dqb_ihardlimit = u->dqb_ihardlimit; - k->dqb_isoftlimit = u->dqb_isoftlimit; - k->dqb_bhardlimit = u->dqb_bhardlimit; - k->dqb_bsoftlimit = u->dqb_bsoftlimit; - k->dqb_curinodes = u->dqb_curinodes; - k->dqb_curspace = u->dqb_curspace; - k->dqb_itime = u->dqb_itime; - k->dqb_btime = u->dqb_btime; -} - static int v2_read_header(struct quota_handle *h, struct v2_disk_dqheader *dqh) { if (h->e2fs_read(&h->qh_qf, 0, dqh, sizeof(struct v2_disk_dqheader)) != @@ -184,27 +151,19 @@ static int v2_check_file(struct quota_handle *h, int type, int fmt) { struct v2_disk_dqheader dqh; int file_magics[] = INITQMAGICS; - int known_versions[] = INIT_V2_VERSIONS; - int version; - if (!v2_read_header(h, &dqh)) + if (fmt != QFMT_VFS_V1) return 0; - if (fmt == QFMT_VFS_V0) - version = 0; - else if (fmt == QFMT_VFS_V1) - version = 1; - else + + if (!v2_read_header(h, &dqh)) return 0; if (ext2fs_le32_to_cpu(dqh.dqh_magic) != file_magics[type]) { if (ext2fs_be32_to_cpu(dqh.dqh_magic) == file_magics[type]) - log_err("Your quota file is stored in wrong " - "endianity.", ""); + log_err("Your quota file is stored in wrong endianity"); return 0; } - if (ext2fs_le32_to_cpu(dqh.dqh_version) > known_versions[type]) - return 0; - if (version != ext2fs_le32_to_cpu(dqh.dqh_version)) + if (V2_VERSION != ext2fs_le32_to_cpu(dqh.dqh_version)) return 0; return 1; } @@ -236,14 +195,13 @@ static int v2_new_io(struct quota_handle *h) int file_magics[] = INITQMAGICS; struct v2_disk_dqheader ddqheader; struct v2_disk_dqinfo ddqinfo; - int version = 1; if (h->qh_fmt != QFMT_VFS_V1) return -1; /* Write basic quota header */ ddqheader.dqh_magic = ext2fs_cpu_to_le32(file_magics[h->qh_type]); - ddqheader.dqh_version = ext2fs_cpu_to_le32(version); + ddqheader.dqh_version = ext2fs_cpu_to_le32(V2_VERSION); if (h->e2fs_write(&h->qh_qf, 0, &ddqheader, sizeof(ddqheader)) != sizeof(ddqheader)) return -1; @@ -320,6 +278,6 @@ static int v2_scan_dquots(struct quota_handle *h, */ static int v2_report(struct quota_handle *h, int verbose) { - log_err("Not Implemented.", ""); + log_err("Not Implemented."); return -1; } diff --git a/lib/quota/quotaio_v2.h b/lib/quota/quotaio_v2.h index 072e36fc..646c698b 100644 --- a/lib/quota/quotaio_v2.h +++ b/lib/quota/quotaio_v2.h @@ -8,15 +8,16 @@ #define GUARD_QUOTAIO_V2_H #include <sys/types.h> -#include "quota.h" +#include "quotaio.h" /* Offset of info header in file */ #define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) -#define INIT_V2_VERSIONS { 1, 1} +/* Supported version of quota-tree format */ +#define V2_VERSION 1 struct v2_disk_dqheader { - u_int32_t dqh_magic; /* Magic number identifying file */ - u_int32_t dqh_version; /* File version */ + __u32 dqh_magic; /* Magic number identifying file */ + __u32 dqh_version; /* File version */ } __attribute__ ((packed)); /* Flags for version specific files */ @@ -24,80 +25,30 @@ struct v2_disk_dqheader { /* Header with type and version specific information */ struct v2_disk_dqinfo { - u_int32_t dqi_bgrace; /* Time before block soft limit becomes + __u32 dqi_bgrace; /* Time before block soft limit becomes * hard limit */ - u_int32_t dqi_igrace; /* Time before inode soft limit becomes + __u32 dqi_igrace; /* Time before inode soft limit becomes * hard limit */ - u_int32_t dqi_flags; /* Flags for quotafile (DQF_*) */ - u_int32_t dqi_blocks; /* Number of blocks in file */ - u_int32_t dqi_free_blk; /* Number of first free block in the list */ - u_int32_t dqi_free_entry; /* Number of block with at least one + __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 */ } __attribute__ ((packed)); -/* Structure of quota for one user on disk */ -struct v2r0_disk_dqblk { - u_int32_t dqb_id; /* id this quota applies to */ - u_int32_t dqb_ihardlimit; /* absolute limit on allocated inodes */ - u_int32_t dqb_isoftlimit; /* preferred inode limit */ - u_int32_t dqb_curinodes; /* current # allocated inodes */ - u_int32_t dqb_bhardlimit; /* absolute limit on disk space - * (in QUOTABLOCK_SIZE) */ - u_int32_t dqb_bsoftlimit; /* preferred limit on disk space - * (in QUOTABLOCK_SIZE) */ - u_int64_t dqb_curspace; /* current space occupied (in bytes) */ - u_int64_t dqb_btime; /* time limit for excessive disk use */ - u_int64_t dqb_itime; /* time limit for excessive inode use */ -} __attribute__ ((packed)); - struct v2r1_disk_dqblk { - u_int32_t dqb_id; /* id this quota applies to */ - u_int32_t dqb_pad; - u_int64_t dqb_ihardlimit; /* absolute limit on allocated inodes */ - u_int64_t dqb_isoftlimit; /* preferred inode limit */ - u_int64_t dqb_curinodes; /* current # allocated inodes */ - u_int64_t dqb_bhardlimit; /* absolute limit on disk space + __u32 dqb_id; /* id this quota applies to */ + __u32 dqb_pad; + __u64 dqb_ihardlimit; /* absolute limit on allocated inodes */ + __u64 dqb_isoftlimit; /* preferred inode limit */ + __u64 dqb_curinodes; /* current # allocated inodes */ + __u64 dqb_bhardlimit; /* absolute limit on disk space * (in QUOTABLOCK_SIZE) */ - u_int64_t dqb_bsoftlimit; /* preferred limit on disk space + __u64 dqb_bsoftlimit; /* preferred limit on disk space * (in QUOTABLOCK_SIZE) */ - u_int64_t dqb_curspace; /* current space occupied (in bytes) */ - u_int64_t dqb_btime; /* time limit for excessive disk use */ - u_int64_t dqb_itime; /* time limit for excessive inode use */ + __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 */ } __attribute__ ((packed)); -/* Structure of quota for communication with kernel */ -struct v2_kern_dqblk { - unsigned int dqb_ihardlimit; - unsigned int dqb_isoftlimit; - unsigned int dqb_curinodes; - unsigned int dqb_bhardlimit; - unsigned int dqb_bsoftlimit; - qsize_t dqb_curspace; - time_t dqb_btime; - time_t dqb_itime; -}; - -/* Structure of quotafile info for communication with kernel (obsolete) */ -struct v2_kern_dqinfo { - unsigned int dqi_bgrace; - unsigned int dqi_igrace; - unsigned int dqi_flags; - unsigned int dqi_blocks; - unsigned int dqi_free_blk; - unsigned int dqi_free_entry; -}; - -/* Structure with gathered statistics from kernel */ -struct v2_dqstats { - u_int32_t lookups; - u_int32_t drops; - u_int32_t reads; - u_int32_t writes; - u_int32_t cache_hits; - u_int32_t allocated_dquots; - u_int32_t free_dquots; - u_int32_t syncs; - u_int32_t version; -}; - #endif |