commit aa83b6f3b2606964e602bed3c6f467641f31891d Author: Abhijith Das <adas@redhat.com> Date: Wed Mar 3 15:01:17 2010 -0600 gfs2_quota: initialize fiemap flags and fix boundary conditions This patch initializes fiemap flags before calling the ioctl and also fixes gfs2_quota for some boundary conditions that prevent some quotas from being set/listed. rhbz#536902 diff --git a/gfs2/quota/check.c b/gfs2/quota/check.c index f33aa17..59c287f 100644 --- a/gfs2/quota/check.c +++ b/gfs2/quota/check.c @@ -222,6 +222,7 @@ read_quota_file(struct gfs2_sbd *sdp, commandline_t *comline, } quota_file_size = statbuf.st_size; /* First find the number of extents in the quota file */ + fmap.fm_flags = 0; fmap.fm_start = 0; fmap.fm_length = (~0ULL); error = ioctl(fd, FS_IOC_FIEMAP, &fmap); @@ -235,6 +236,7 @@ read_quota_file(struct gfs2_sbd *sdp, commandline_t *comline, fprintf(stderr, "malloc error (%d): %s\n", errno, strerror(errno)); goto out; } + fmap2->fm_flags = 0; fmap2->fm_start = 0; fmap2->fm_length = (~0ULL); fmap2->fm_extent_count = fmap.fm_mapped_extents; @@ -264,6 +266,7 @@ read_quota_file(struct gfs2_sbd *sdp, commandline_t *comline, } gfs2_quota_in(&q, buf); id = (offset / sizeof(struct gfs2_quota)) >> 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) { @@ -274,7 +277,7 @@ read_quota_file(struct gfs2_sbd *sdp, commandline_t *comline, } offset += sizeof(struct gfs2_quota); - } while ((offset + sizeof(struct gfs2_quota)) < + } while ((offset + sizeof(struct gfs2_quota)) <= end); } } diff --git a/gfs2/quota/main.c b/gfs2/quota/main.c index e8b0fa2..36b6f2d 100644 --- a/gfs2/quota/main.c +++ b/gfs2/quota/main.c @@ -321,7 +321,7 @@ read_quota_internal(int fd, uint32_t id, int id_type, struct gfs2_quota *q) if (error < 0) die("failed to read from quota file: %s\n", strerror(errno)); if (error != sizeof(struct gfs2_quota)) - die("Couldn't read %u bytes from quota file at offset %llu\n", + die("Couldn't read %lu bytes from quota file at offset %llu\n", sizeof(struct gfs2_quota), (unsigned long long)offset); gfs2_quota_in(q, buf); } @@ -360,8 +360,8 @@ do_reset(struct gfs2_sbd *sdp, commandline_t *comline) if (!*comline->filesystem) die("need a filesystem to work on\n"); - printf("This operation will permanently erase all quota information. " - "You will have to re-assign all quota limit/warn values. " + printf("This operation will permanently erase all quota information.\n" + "You will have to re-assign all quota limit/warn values.\n" "Proceed [y/N]? "); c = getchar(); if (c != 'y' && c != 'Y') @@ -411,8 +411,9 @@ do_list(struct gfs2_sbd *sdp, commandline_t *comline) { int fd; struct gfs2_quota q; - uint32_t startid, endid; - int id_type; + char buf[sizeof(struct gfs2_quota)]; + uint64_t offset; + uint32_t id, startid; int pass = 0; int error = 0; char quota_file[BUF_SIZE]; @@ -447,6 +448,7 @@ do_list(struct gfs2_sbd *sdp, commandline_t *comline) } quota_file_size = statbuf.st_size; /* First find the number of extents in the quota file */ + fmap.fm_flags = 0; fmap.fm_start = 0; fmap.fm_length = (~0ULL); error = ioctl(fd, FS_IOC_FIEMAP, &fmap); @@ -460,6 +462,7 @@ do_list(struct gfs2_sbd *sdp, commandline_t *comline) fprintf(stderr, "malloc error (%d): %s\n", errno, strerror(errno)); goto out; } + fmap2->fm_flags = 0; fmap2->fm_start = 0; fmap2->fm_length = (~0ULL); fmap2->fm_extent_count = fmap.fm_mapped_extents; @@ -478,19 +481,26 @@ do_list(struct gfs2_sbd *sdp, commandline_t *comline) end = end > quota_file_size ? quota_file_size : end; startid = DIV_RU(fe->fe_logical, sizeof(struct gfs2_quota)); - endid = end /(2 * sizeof(struct gfs2_quota)); if (startid % 2 != pass) startid++; - - startid = DIV_RU(startid, 2); - id_type = pass == 0 ? GQ_ID_USER : GQ_ID_GROUP; + offset = startid * sizeof(struct gfs2_quota); do { - read_quota_internal(fd, startid, id_type, &q); + memset(buf, 0, sizeof(struct gfs2_quota)); + /* read hidden quota file here */ + lseek(fd, offset, SEEK_SET); + error = read(fd, buf, sizeof(struct gfs2_quota)); + 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; if (q.qu_limit || q.qu_warn || q.qu_value) - print_quota(comline, (pass) ? FALSE : TRUE, startid, + print_quota(comline, (pass) ? FALSE : TRUE, id, &q, &sdp->sd_sb); - startid++; - } while (startid < endid); + offset += 2 * sizeof(struct gfs2_quota); + } while (offset < end); } if (!pass) { pass = 1; @@ -666,10 +676,10 @@ do_set(struct gfs2_sbd *sdp, commandline_t *comline) int fd; uint64_t offset; uint64_t new_value; - int error; char quota_file[BUF_SIZE]; char id_str[16]; struct stat stat_buf; + struct gfs2_quota q; char *fs; if (!*comline->filesystem) @@ -685,7 +695,7 @@ do_set(struct gfs2_sbd *sdp, commandline_t *comline) strcpy(quota_file, sdp->metafs_path); strcat(quota_file, "/quota"); - fd = open(quota_file, O_WRONLY); + fd = open(quota_file, O_RDWR); if (fd < 0) { close(sdp->metafs_fd); cleanup_metafs(sdp); @@ -735,76 +745,22 @@ do_set(struct gfs2_sbd *sdp, commandline_t *comline) goto out; } - new_value = cpu_to_be64(new_value); - /* - * Hack to force writing the entire gfs2_quota structure to - * the quota file instead of just the limit or warn values. - * This is because of a bug in gfs2 which doesn't extend - * the quotafile appropriately to write the usage value of a - * given id. For instance, if you write a limit value (8 bytes) - * for userid x at offset 2*x, gfs2 will not extend the file and write - * 8 bytes at offset (2*x + 16) when it has to update the usage - * value for id x. Therefore, we extend the quota file to - * a struct gfs2_quota boundary. i.e. The size of the quota file - * will always be a multiple of sizeof(struct gfs2_quota) - */ + memset(&q, 0, sizeof(struct gfs2_quota)); if (fstat(fd, &stat_buf)) { fprintf(stderr, "stat failed: %s\n", strerror(errno)); goto out; } - if (stat_buf.st_size < (offset + sizeof(struct gfs2_quota))) { - struct gfs2_quota tmp; - memset((void*)(&tmp), 0, sizeof(struct gfs2_quota)); - switch (comline->operation) { - case GQ_OP_LIMIT: - tmp.qu_limit = new_value; break; - case GQ_OP_WARN: - tmp.qu_warn = new_value; break; - } - - lseek(fd, offset, SEEK_SET); - error = write(fd, (void*)(&tmp), sizeof(struct gfs2_quota)); - if (error != sizeof(struct gfs2_quota)) { - fprintf(stderr, "can't write quota file (%d): %s\n", - error, strerror(errno)); - goto out; - } - /* Also, if the id type is USER, append another empty - * struct gfs2_quota for the GROUP with the same id - */ - if (comline->id_type == GQ_ID_USER) { - memset((void*)(&tmp), 0, sizeof(struct gfs2_quota)); - error = write(fd, (void*)(&tmp), sizeof(struct gfs2_quota)); - if (error != sizeof(struct gfs2_quota)) { - fprintf(stderr, "can't write quota file (%d): %s\n", - error, strerror(errno)); - goto out; - } - } - } else { - switch (comline->operation) { - case GQ_OP_LIMIT: - offset += (unsigned long)(&((struct gfs2_quota *) NULL)->qu_limit); - break; - - case GQ_OP_WARN: - offset += (unsigned long)(&((struct gfs2_quota *) NULL)->qu_warn); - break; - - default: - fprintf(stderr, "invalid operation\n"); - goto out; - }; + if (stat_buf.st_size >= (offset + sizeof(struct gfs2_quota))) + read_quota_internal(fd, comline->id, comline->id_type, &q); - lseek(fd, offset, SEEK_SET); - error = write(fd, (char*)&new_value, sizeof(uint64_t)); - if (error != sizeof(uint64_t)) { - fprintf(stderr, "can't write quota file (%d): %s\n", - error, strerror(errno)); - goto out; - } + switch (comline->operation) { + case GQ_OP_LIMIT: + q.qu_limit = new_value; break; + case GQ_OP_WARN: + q.qu_warn = new_value; break; } + write_quota_internal(fd, comline->id, comline->id_type, &q); fs = mp2fsname(comline->filesystem); sprintf(id_str, "%d", comline->id); set_sysfs(fs, comline->id_type == GQ_ID_USER ?