Whamcloud - gitweb
libquota: quota file read support
authorNiu <niu@whamcloud.com>
Mon, 14 Nov 2011 15:58:28 +0000 (10:58 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Mon, 14 Nov 2011 15:58:28 +0000 (10:58 -0500)
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@whamcloud.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
lib/quota/mkquota.c
lib/quota/mkquota.h
lib/quota/quotaio.c
lib/quota/quotaio.h
lib/quota/quotaio_tree.c
lib/quota/quotaio_tree.h
lib/quota/quotaio_v2.c

index 3921da9..2abb2d4 100644 (file)
@@ -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;
+}
index 8d0a8ce..4fbaedd 100644 (file)
@@ -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);
 
index 4af0184..6edb0b0 100644 (file)
@@ -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 = &quotafile_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)
index fa71762..f8cc1f1 100644 (file)
@@ -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,
index b8583b9..9080e77 100644 (file)
@@ -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);
index a23777d..37c15ce 100644 (file)
@@ -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);
 
index 6b5078b..e658706 100644 (file)
@@ -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.