Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 35adedb8830cf948b43b86231991124b > files > 112

gfs2-utils-0.1.62-39.el5.src.rpm

commit 170291d3fd107e78e5bf9dd106c877e403030f35
Author: Abhijith Das <adas@redhat.com>
Date:   Fri Apr 30 11:05:23 2010 -0500

    gfs2_quota: Keep quota file length always sizeof(struct gfs2_quota) aligned
    
    This patch rounds up the quota filesize to the nearest
    sizeof(struct gfs2_quota). It also fixes read/write of
    quotas split across page boundaries that sometimes get
    missed out.
    
    Resolves: rhbz#585085
    Signed-off-by: Abhi Das <adas@redhat.com>

diff --git a/gfs2/quota/check.c b/gfs2/quota/check.c
index 0a1c1e3..2635725 100644
--- a/gfs2/quota/check.c
+++ b/gfs2/quota/check.c
@@ -188,10 +188,7 @@ read_quota_file(struct gfs2_sbd *sdp, commandline_t *comline,
 		osi_list_t *uid, osi_list_t *gid)
 {
 	int fd;
-	char buf[sizeof(struct gfs2_quota)];
-	struct gfs2_quota q;
-	uint64_t offset = 0;
-	uint32_t id, startid;
+	uint32_t id, startq;
 	int error = 0;
 	char quota_file[BUF_SIZE];
 	uint64_t quota_file_size = 0;
@@ -249,36 +246,51 @@ read_quota_file(struct gfs2_sbd *sdp, commandline_t *comline,
 		int i;
 		for (i=0; i<fmap2->fm_mapped_extents; i++) {
 			struct fiemap_extent *fe = &fmap2->fm_extents[i];
-			uint64_t end = fe->fe_logical + fe->fe_length;
+			uint64_t end = fe->fe_logical + fe->fe_length, val_off;
+			unsigned int v_off;
 
 			end = end > quota_file_size ? quota_file_size : end;
-			startid = DIV_RU(fe->fe_logical, sizeof(struct gfs2_quota));
-			offset = startid * sizeof(struct gfs2_quota);
-			do {
-				memset(buf, 0, sizeof(struct gfs2_quota));
+			/* we only need to get the value fields, not the whole quota 
+			 * This also works when struct gfs2_quota straddle page 
+			 * boundaries. Getting only the value field avoids the 
+			 * complexity of fetching two parts of the struct gfs2_quota
+			 * from two successive pages
+			 */
+			/* offset of the value field within struct gfs2_quota */
+			v_off = (unsigned long)(&((struct gfs2_quota *)NULL)->qu_value);
+			/* startq could be at the end of previous extent... */
+			startq = fe->fe_logical / sizeof(struct gfs2_quota);
+			/* but the value field could be in this extent */
+			if ((startq * sizeof(struct gfs2_quota) + v_off) >= fe->fe_logical)
+				val_off = startq * sizeof(struct gfs2_quota) + v_off;
+			else /* if the start of the extent doesn't have a split quota */
+				val_off = ++startq * sizeof(struct gfs2_quota) + v_off;
+
+			while ((val_off + sizeof(uint64_t)) <= end)
+			{
+				uint64_t value;
 				/* read hidden quota file here */
-				lseek(fd, offset, SEEK_SET);
-				error = read(fd, buf, sizeof(struct gfs2_quota));
+				lseek(fd, val_off, SEEK_SET);
+				error = read(fd, (unsigned char*)&value, sizeof(uint64_t));
 				if (error < 0) {
 					fprintf(stderr, "read error (%d): %s\n", 
 						errno, strerror(errno));
 					goto fmap2_free;
 				}
-				gfs2_quota_in(&q, buf);
-				id = (offset / sizeof(struct gfs2_quota)) >> 1;
+				value = be64_to_cpu(value);
+				id = startq >> 1;
 				/* We want value in 512 byte blocks (1 << 9 = 512) */
-				q.qu_value <<= sdp->sd_sb.sb_bsize_shift - 9;
-
-				if (q.qu_value) {
-					if (id * sizeof(struct gfs2_quota) * 2 == offset)
-						add_value(uid, id, q.qu_value);
+				value <<= sdp->sd_sb.sb_bsize_shift - 9;
+				if (value) {
+					/* if startq is even, it's a uid, else gid */
+					if (startq % 2)
+						add_value(gid, id, value);
 					else
-						add_value(gid, id, q.qu_value);
+						add_value(uid, id, value);
 				}
-
-				offset += sizeof(struct gfs2_quota);
-			} while ((offset + sizeof(struct gfs2_quota)) <= 
-				 end);
+				startq++;
+				val_off += sizeof(struct gfs2_quota);
+			}
 		}
 	}
 fmap2_free:
@@ -477,12 +489,13 @@ set_list(struct gfs2_sbd *sdp, commandline_t *comline, int user,
 	int fd;
 	osi_list_t *tmp;
 	values_t *v;
-	uint64_t offset;
+	uint64_t offset, max_off = 0;
 	int64_t value;
 	int error;
 	char quota_file[BUF_SIZE];
 	char id_str[16];
 	char *fs;
+	struct stat st;
 
 	strcpy(sdp->path_name, comline->filesystem);
 	check_for_gfs2(sdp);
@@ -505,6 +518,8 @@ set_list(struct gfs2_sbd *sdp, commandline_t *comline, int user,
 
 		offset = (2 * (uint64_t)v->v_id + ((user) ? 0 : 1)) *
 			sizeof(struct gfs2_quota);
+		if (offset > max_off)
+			max_off = offset;
 		offset += (unsigned long)(&((struct gfs2_quota *)NULL)->qu_value);
 
 		value = v->v_blocks * multiplier;
@@ -525,7 +540,21 @@ set_list(struct gfs2_sbd *sdp, commandline_t *comline, int user,
 		set_sysfs(fs, (user) ? "quota_refresh_user" :
 			  "quota_refresh_group", id_str);
 	}
-
+	/* If we wrote a value that extended the quota file size, 
+	 * round the size off to the nearest quota boundary
+	 */
+	error = fstat(fd, &st);
+	if (error) {
+		fprintf(stderr, "can't stat quota file (%d): %s\n",
+			error, strerror(errno));
+		goto out;
+	}
+	if (st.st_size < (max_off + sizeof(struct gfs2_quota))) {
+		error = ftruncate(fd, (max_off + sizeof(struct gfs2_quota)));
+		if (error)
+			fprintf(stderr, "can't truncate quota file(%d): %s\n",
+				error, strerror(errno));
+	}
 out:
 	close(fd);
 	close(sdp->metafs_fd);
@@ -578,6 +607,5 @@ do_quota_init(struct gfs2_sbd *sdp, commandline_t *comline)
 	set_list(sdp, comline, FALSE, &fs_gid, 1);
 	
 	do_sync(sdp, comline);
-
 	do_check(sdp, comline);
 }
diff --git a/gfs2/quota/main.c b/gfs2/quota/main.c
index 7cd1b7d..07aed6c 100644
--- a/gfs2/quota/main.c
+++ b/gfs2/quota/main.c
@@ -340,7 +340,7 @@ read_quota_internal(int fd, uint32_t id, int id_type, struct gfs2_quota *q)
 inline void 
 write_quota_internal(int fd, uint32_t id, int id_type, struct gfs2_quota *q)
 {
-	/* seek to the appropriate offset in the quota file and read the
+	/* seek to the appropriate offset in the quota file and write the
 	   quota info */
 	uint64_t offset;
 	char buf[256];