This makes memory management easier because when the quota context is released, all of the quota file handles get released automatically. Signed-off-by: "Theodore Ts'o" <tytso@xxxxxxx> Cc: adityakali@xxxxxxxxxx --- lib/quota/mkquota.c | 26 ++++++++++++++++--------- lib/quota/quotaio.c | 55 +++++++++++++++++++++++++++++++++++++++++++---------- lib/quota/quotaio.h | 6 ++++-- 3 files changed, 66 insertions(+), 21 deletions(-) diff --git a/lib/quota/mkquota.c b/lib/quota/mkquota.c index bb8482b..58803d0 100644 --- a/lib/quota/mkquota.c +++ b/lib/quota/mkquota.c @@ -183,7 +183,7 @@ errcode_t quota_write_inode(quota_ctx_t qctx, int qtype) } 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)); @@ -251,9 +251,10 @@ 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) { @@ -263,6 +264,7 @@ errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs, int qtype) 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); @@ -283,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; @@ -298,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); @@ -541,7 +552,7 @@ errcode_t quota_update_limits(quota_ctx_t qctx, ext2_ino_t qf_ino, int type) return err; } - err = quota_file_open(qh, qctx->fs, qf_ino, type, -1, 0); + err = quota_file_open(qctx, qh, qf_ino, type, -1, 0); if (err) { log_err("Open quota file failed"); goto out; @@ -549,7 +560,7 @@ errcode_t quota_update_limits(quota_ctx_t qctx, ext2_ino_t qf_ino, int type) quota_read_all_dquots(qh, qctx, 1); - err = quota_file_close(qh); + err = quota_file_close(qctx, qh); if (err) { log_err("Cannot finish IO on new quotafile: %s", strerror(errno)); @@ -575,15 +586,12 @@ errcode_t quota_compare_and_update(quota_ctx_t qctx, int qtype, struct dquot *dq; dnode_t *n; dict_t *dict = qctx->quota_dict[qtype]; - ext2_ino_t qf_ino; errcode_t err = 0; if (!dict) goto out; - qf_ino = qtype == USRQUOTA ? fs->super->s_usr_quota_inum : - fs->super->s_grp_quota_inum; - err = quota_file_open(&qh, fs, qf_ino, qtype, -1, 0); + err = quota_file_open(qctx, &qh, 0, qtype, -1, 0); if (err) { log_err("Open quota file failed"); goto out; @@ -612,7 +620,7 @@ errcode_t quota_compare_and_update(quota_ctx_t qctx, int qtype, *usage_inconsistent = scan_data.usage_is_inconsistent; out_close_qh: - err = quota_file_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) diff --git a/lib/quota/quotaio.c b/lib/quota/quotaio.c index a95a1f9..65fccaa 100644 --- a/lib/quota/quotaio.c +++ b/lib/quota/quotaio.c @@ -197,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; @@ -210,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; @@ -231,17 +260,22 @@ 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; + 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; + 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) @@ -307,12 +341,12 @@ errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs, int type, in 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 +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) @@ -366,7 +400,8 @@ errcode_t quota_file_close(struct quota_handle *h) 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; } diff --git a/lib/quota/quotaio.h b/lib/quota/quotaio.h index d3820a4..7ca7830 100644 --- a/lib/quota/quotaio.h +++ b/lib/quota/quotaio.h @@ -53,6 +53,7 @@ typedef struct quota_ctx *quota_ctx_t; struct quota_ctx { ext2_filsys fs; dict_t *quota_dict[MAXQUOTAS]; + struct quota_handle *quota_file[MAXQUOTAS]; }; /* @@ -105,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, @@ -171,7 +173,7 @@ extern struct quotafile_ops quotafile_ops_meta; /* 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); @@ -180,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); -- 1.9.0 -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html