All of lore.kernel.org
 help / color / mirror / Atom feed
From: Niu <niu@whamcloud.com>
To: adityakali@google.com
Cc: linux-ext4@vger.kernel.org
Subject: [PATCH 1/3] libquota: quota file read support
Date: Sun, 06 Nov 2011 21:36:39 +0800	[thread overview]
Message-ID: <4EB68D67.909@whamcloud.com> (raw)

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>
---
 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 = &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)
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

             reply	other threads:[~2011-11-06 13:36 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-11-06 13:36 Niu [this message]
2011-11-14 15:58 ` [PATCH 1/3] libquota: quota file read support Ted Ts'o

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4EB68D67.909@whamcloud.com \
    --to=niu@whamcloud.com \
    --cc=adityakali@google.com \
    --cc=linux-ext4@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.