Gitweb:
http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 170291d3fd107e78e5bf9dd106c877e403030f35
Parent: 14ccf8c485c8aeda5a28fe60e5122979eeb3b517
Author: Abhijith Das <adas(a)redhat.com>
AuthorDate: Fri Apr 30 11:05:23 2010 -0500
Committer: Abhijith Das <adas(a)redhat.com>
CommitterDate: 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(a)redhat.com>
---
gfs2/quota/check.c | 80 +++++++++++++++++++++++++++++++++++-----------------
gfs2/quota/main.c | 2 +-
2 files changed, 55 insertions(+), 27 deletions(-)
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];