This patch adds read quota file support, which includes: - Improve scan dquot APIs & fix defects in scan dquot functions; - Implement quota_file_open(); - Introduce quota_update_inode() to update usage in old quota file, and keep the limits unchanged. Signed-off-by: Niu Yawei <niu@xxxxxxxxxxxxx> --- lib/quota/mkquota.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++ lib/quota/mkquota.h | 1 + lib/quota/quotaio.c | 46 ++++++++++++++++++++- lib/quota/quotaio.h | 6 ++- lib/quota/quotaio_tree.c | 25 ++++++++---- lib/quota/quotaio_tree.h | 2 +- lib/quota/quotaio_v2.c | 20 ++++++++-- 7 files changed, 179 insertions(+), 18 deletions(-) diff --git a/lib/quota/mkquota.c b/lib/quota/mkquota.c index 3921da9..2abb2d4 100644 --- a/lib/quota/mkquota.c +++ b/lib/quota/mkquota.c @@ -413,3 +413,100 @@ errcode_t quota_compute_usage(quota_ctx_t qctx) return 0; } + +struct scan_dquots_data { + quota_ctx_t qctx; + int limit_only; /* read limit only */ +}; + +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 dquot *dq; + + dq = get_dq(qctx->quota_dict[dquot->dq_h->qh_type], 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_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; + } + return 0; +} + +/* + * 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) +{ + struct scan_dquots_data scan_data; + + scan_data.qctx = qctx; + scan_data.limit_only = limit_only; + + return qh->qh_ops->scan_dquots(qh, scan_dquots_callback, &scan_data); +} + +/* + * Write all memory dquots into quota file + */ +static errcode_t quota_write_all_dquots(struct quota_handle *qh, + quota_ctx_t qctx) +{ + errcode_t err; + + err = ext2fs_read_bitmaps(qctx->fs); + if (err) + return err; + write_dquots(qctx->quota_dict[qh->qh_type], qh); + ext2fs_mark_bb_dirty(qctx->fs); + qctx->fs->flags &= ~EXT2_FLAG_SUPER_ONLY; + ext2fs_write_bitmaps(qctx->fs); + return 0; +} + +/* + * Update usage of in quota file, limits keep unchaged + */ +errcode_t quota_update_inode(quota_ctx_t qctx, ext2_ino_t qf_ino, int type) +{ + struct quota_handle *qh; + errcode_t err; + + if (!qctx) + return 0; + + err = ext2fs_get_mem(sizeof(struct quota_handle), &qh); + if (err) { + log_err("Unable to allocate quota handle", ""); + return err; + } + + err = quota_file_open(qh, qctx->fs, qf_ino, type, -1, EXT2_FILE_WRITE); + if (err) { + 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); + if (err) { + log_err("Cannot finish IO on new quotafile: %s", + strerror(errno)); + if (qh->qh_qf.e2_file) + ext2fs_file_close(qh->qh_qf.e2_file); + } +out: + ext2fs_free_mem(&qh); + return err; +} diff --git a/lib/quota/mkquota.h b/lib/quota/mkquota.h index 8d0a8ce..4fbaedd 100644 --- a/lib/quota/mkquota.h +++ b/lib/quota/mkquota.h @@ -51,6 +51,7 @@ void quota_data_add(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, 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); diff --git a/lib/quota/quotaio.c b/lib/quota/quotaio.c index 4af0184..6edb0b0 100644 --- a/lib/quota/quotaio.c +++ b/lib/quota/quotaio.c @@ -217,10 +217,50 @@ 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, - int type, int fmt, int flags) + ext2_ino_t qf_ino, int type, int fmt, int flags) { - log_err("Not Implemented.", ""); - return -1; + ext2_file_t e2_file; + errcode_t err; + + if (fmt == -1) + fmt = QFMT_VFS_V1; + + err = ext2fs_read_bitmaps(fs); + if (err) + return err; + + 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: %d", err); + return err; + } + 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_io_flags = 0; + h->qh_type = type; + h->qh_fmt = fmt; + memset(&h->qh_info, 0, sizeof(h->qh_info)); + h->qh_ops = "afile_ops_2; + + 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; + } + + 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; + } + + return 0; } static errcode_t quota_inode_init_new(ext2_filsys fs, ext2_ino_t ino) diff --git a/lib/quota/quotaio.h b/lib/quota/quotaio.h index fa71762..f8cc1f1 100644 --- a/lib/quota/quotaio.h +++ b/lib/quota/quotaio.h @@ -120,7 +120,8 @@ struct quotafile_ops { /* Scan quotafile and call callback on every structure */ int (*scan_dquots) (struct quota_handle *h, int (*process_dquot) (struct dquot *dquot, - char *dqname)); + void *data), + void *data); /* Function to print format specific file information */ int (*report) (struct quota_handle *h, int verbose); }; @@ -139,7 +140,8 @@ static inline void mark_quotafile_info_dirty(struct quota_handle *h) /* 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, - int type, int fmt, int flags); + ext2_ino_t qf_ino, int type, int fmt, int flags); + /* Create new quotafile of specified format on given filesystem */ errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs, diff --git a/lib/quota/quotaio_tree.c b/lib/quota/quotaio_tree.c index b8583b9..9080e77 100644 --- a/lib/quota/quotaio_tree.c +++ b/lib/quota/quotaio_tree.c @@ -537,7 +537,8 @@ struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id) #define get_bit(bmp, ind) ((bmp)[(ind) >> 3] & (1 << ((ind) & 7))) static int report_block(struct dquot *dquot, uint blk, char *bitmap, - int (*process_dquot) (struct dquot *, char *)) + int (*process_dquot) (struct dquot *, void *), + void *data) { struct qtree_mem_dqinfo *info = &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; @@ -557,8 +558,12 @@ static int report_block(struct dquot *dquot, uint blk, char *bitmap, for (i = 0; i < qtree_dqstr_in_blk(info); i++, ddata += info->dqi_entry_size) if (!qtree_entry_unused(info, ddata)) { + dquot->dq_dqb.u.v2_mdqb.dqb_off = + (blk << QT_BLKSIZE_BITS) + + sizeof(struct qt_disk_dqdbheader) + + i * info->dqi_entry_size; info->dqi_ops->disk2mem_dqblk(dquot, ddata); - if (process_dquot(dquot, NULL) < 0) + if (process_dquot(dquot, data) < 0) break; } freedqbuf(buf); @@ -577,7 +582,8 @@ static void check_reference(struct quota_handle *h, uint blk) } static int report_tree(struct dquot *dquot, uint blk, int depth, char *bitmap, - int (*process_dquot) (struct dquot *, char *)) + int (*process_dquot) (struct dquot *, void *), + void *data) { int entries = 0, i; dqbuf_t buf = getdqbuf(); @@ -593,16 +599,18 @@ static int report_tree(struct dquot *dquot, uint blk, int depth, char *bitmap, check_reference(dquot->dq_h, blk); if (blk && !get_bit(bitmap, blk)) entries += report_block(dquot, blk, bitmap, - process_dquot); + process_dquot, data); } } else { - for (i = 0; i < QT_BLKSIZE >> 2; i++) + for (i = 0; i < QT_BLKSIZE >> 2; i++) { blk = ext2fs_le32_to_cpu(ref[i]); if (blk) { check_reference(dquot->dq_h, blk); entries += report_tree(dquot, blk, depth + 1, - bitmap, process_dquot); + bitmap, process_dquot, + data); } + } } freedqbuf(buf); return entries; @@ -619,7 +627,8 @@ static uint find_set_bits(char *bmp, int blocks) } int qtree_scan_dquots(struct quota_handle *h, - int (*process_dquot) (struct dquot *, char *)) + int (*process_dquot) (struct dquot *, void *), + void *data) { char *bitmap; struct v2_mem_dqinfo *v2info = &h->qh_info.u.v2_mdqi; @@ -635,7 +644,7 @@ int qtree_scan_dquots(struct quota_handle *h, return -1; } v2info->dqi_used_entries = report_tree(dquot, QT_TREEOFF, 0, bitmap, - process_dquot); + process_dquot, data); v2info->dqi_data_blocks = find_set_bits(bitmap, info->dqi_blocks); ext2fs_free_mem(&bitmap); ext2fs_free_mem(&dquot); diff --git a/lib/quota/quotaio_tree.h b/lib/quota/quotaio_tree.h index a23777d..37c15ce 100644 --- a/lib/quota/quotaio_tree.h +++ b/lib/quota/quotaio_tree.h @@ -56,7 +56,7 @@ struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id); void qtree_delete_dquot(struct dquot *dquot); int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk); int qtree_scan_dquots(struct quota_handle *h, - int (*process_dquot) (struct dquot *, char *)); + int (*process_dquot) (struct dquot *, void *), void *data); int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info); diff --git a/lib/quota/quotaio_v2.c b/lib/quota/quotaio_v2.c index 6b5078b..e658706 100644 --- a/lib/quota/quotaio_v2.c +++ b/lib/quota/quotaio_v2.c @@ -28,7 +28,8 @@ static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id); static int v2_commit_dquot(struct dquot *dquot); static int v2_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot *dquot, - char *dqname)); + void *data), + void *data); static int v2_report(struct quota_handle *h, int verbose); struct quotafile_ops quotafile_ops_2 = { @@ -213,7 +214,17 @@ static int v2_check_file(struct quota_handle *h, int type, int fmt) */ static int v2_init_io(struct quota_handle *h) { - log_err("Not Implemented.", ""); + struct v2_disk_dqinfo ddqinfo; + + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size = + sizeof(struct v2r1_disk_dqblk); + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_ops = &v2r1_fmt_ops; + + /* Read information about quotafile */ + if (h->e2fs_read(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, + sizeof(ddqinfo)) != sizeof(ddqinfo)) + return -1; + v2_disk2memdqinfo(&h->qh_info, &ddqinfo); return 0; } @@ -297,9 +308,10 @@ static int v2_commit_dquot(struct dquot *dquot) } static int v2_scan_dquots(struct quota_handle *h, - int (*process_dquot) (struct dquot *, char *)) + int (*process_dquot) (struct dquot *, void *), + void *data) { - return qtree_scan_dquots(h, process_dquot); + return qtree_scan_dquots(h, process_dquot, data); } /* Report information about quotafile. -- 1.7.1 -- 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