cluster: RHEL56 - gfs2_quota: Keep quota file length always sizeof(struct gfs2_quota) aligned
by Abhijith Das
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];
13 years, 11 months
cluster: RHEL56 - gfs2_convert: Does not convert full gfs1 filesystems
by Abhijith Das
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 14ccf8c485c8aeda5a28fe60e5122979eeb3b517
Parent: 4e102cbef05a8d57b063b56346ca439cd580c924
Author: Abhijith Das <adas(a)redhat.com>
AuthorDate: Fri Apr 30 10:49:12 2010 -0500
Committer: Abhijith Das <adas(a)redhat.com>
CommitterDate: Fri Apr 30 10:49:12 2010 -0500
gfs2_convert: Does not convert full gfs1 filesystems
We now check to see if the number of blocks we intend
to allocate while creating GFS2 file system structures
are less than the available free blocks. If not enough
blocks are available, we reduce the journal size (1MB
at a time) until we can fit everything in.
Resolves: rhbz#585081
Signed-off-by: Abhi Das <adas(a)redhat.com>
---
gfs2/convert/gfs2_convert.c | 107 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 107 insertions(+), 0 deletions(-)
diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index f28aac4..8835a5b 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -68,6 +68,8 @@
#define GFS_FORMAT_FS (1309) /* Filesystem (all-encompassing) */
#define GFS_FORMAT_MULTI (1401) /* Multi-Host */
+#define DIV_RU(x, y) (((x) + (y) - 1) / (y))
+
struct gfs1_rgrp {
struct gfs2_meta_header rg_header; /* hasn't changed from gfs1 to 2 */
uint32_t rg_flags;
@@ -2007,6 +2009,100 @@ static void conv_build_jindex(struct gfs2_sbd *sdp)
inode_put(&sdp->md.jiinode);
}
+static unsigned int total_file_blocks(struct gfs2_sbd *sdp,
+ uint64_t filesize, int journaled)
+{
+ unsigned int data_blks = 0, meta_blks = 0, total_blks;
+ unsigned int max, height, bsize;
+ uint64_t *arr;
+
+ /* Now find the total meta blocks required for data_blks */
+ if (filesize <= sdp->bsize - sizeof(struct gfs2_dinode)) {
+ total_blks = 1; /* stuffed inode */
+ goto out;
+ }
+
+ if (journaled) {
+ arr = sdp->sd_jheightsize;
+ max = sdp->sd_max_jheight;
+ bsize = sdp->sd_jbsize;
+ } else {
+ arr = sdp->sd_heightsize;
+ max = sdp->sd_max_height;
+ bsize = sdp->bsize;
+ }
+ data_blks = DIV_RU(filesize, bsize); /* total data blocks reqd */
+
+ for (height = 0; height < max; height++)
+ if (arr[height] >= filesize)
+ break;
+ if (height == 1) {
+ total_blks = data_blks + 1; /* dinode has direct ptrs to data blocks */
+ goto out;
+ }
+
+ meta_blks = DIV_RU(data_blks, sdp->sd_inptrs);
+ total_blks = data_blks + meta_blks;
+out:
+ return data_blks + meta_blks;
+}
+
+/* We check if the GFS2 filesystem files/structures created after the call to
+ * check_fit() in main() will fit in the currently available free blocks
+ */
+static int check_fit(struct gfs2_sbd *sdp)
+{
+ unsigned int blks_need = 0, blks_avail = sdp->blks_total - sdp->blks_alloced;
+
+ /* build_master() */
+ blks_need++; /*creation of master dir inode - 1 block */
+
+ /* conv_build_jindex() */
+ {
+ blks_need++; /* creation of 'jindex' disk inode */
+ /* creation of journals */
+ blks_need += sdp->md.journals *
+ total_file_blocks(sdp, sdp->jsize << 20, 1);
+ }
+ /* build_per_node() */
+ {
+ blks_need++; /* creation of 'per_node' dir inode */
+ /* njourn x (inum_range + statfs_change + quota_change inodes) */
+ blks_need += sdp->md.journals * 3;
+ /* quota change inodes are prealloced */
+ blks_need += sdp->md.journals *
+ total_file_blocks(sdp, sdp->qcsize << 20, 1);
+ }
+ /* build_inum() */
+ blks_need++; /* creation of 'inum' disk inode */
+
+ /* build_statfs() */
+ blks_need++; /* creation of 'statfs' disk inode */
+
+ /* build_rindex() */
+ {
+ osi_list_t *tmp, *head;
+ unsigned int rg_count = 0;
+
+ blks_need++; /* creationg of 'rindex' disk inode */
+ /* find the total # of rindex entries, gives size of rindex inode */
+ for (head = &sdp->rglist, tmp = head->next; tmp != head;
+ tmp = tmp->next)
+ rg_count++;
+ blks_need +=
+ total_file_blocks(sdp, rg_count * sizeof(struct gfs2_rindex), 1);
+ }
+ /* build_quota() */
+ blks_need++; /* quota inode block and uid=gid=0 quota - total 1 block */
+
+ /* Up until this point we require blks_need blocks. We don't
+ * include the blocks freed by the next step (remove_obsolete_gfs1)
+ * because it's possible for us to exceed the available blocks
+ * before this step */
+
+ return blks_avail > blks_need;
+}
+
/* ------------------------------------------------------------------------- */
/* main - mainline code */
/* ------------------------------------------------------------------------- */
@@ -2094,8 +2190,19 @@ int main(int argc, char **argv)
/* Create our system files and directories. */
/* ---------------------------------------------- */
if (!error) {
+ int jreduce = 0;
/* Now we've got to treat it as a gfs2 file system */
compute_constants(&sb2);
+
+ /* Check if all the files we're about to create will
+ * fit into the space remaining on the device */
+ while (!check_fit(&sb2)) {
+ sb2.jsize--; /* reduce jsize by 1MB each time */
+ jreduce = 1;
+ }
+ if (jreduce)
+ log_notice("Reduced journal size to %u MB to accommodate "
+ "GFS2 file system structures.\n", sb2.jsize);
/* Build the master subdirectory. */
build_master(&sb2); /* Does not do inode_put */
sb2.sd_sb.sb_master_dir = sb2.master_dir->i_di.di_num;
13 years, 11 months
cluster: RHEL56 - gfs2_convert: gfs2_convert doesn't convert indirectly-pointed extended attributes correctly
by Abhijith Das
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 4e102cbef05a8d57b063b56346ca439cd580c924
Parent: 7a9640a8e3c1c3430f5705affdc38772f0f4a1ab
Author: Abhijith Das <adas(a)redhat.com>
AuthorDate: Fri Apr 30 10:47:09 2010 -0500
Committer: Abhijith Das <adas(a)redhat.com>
CommitterDate: Fri Apr 30 10:47:09 2010 -0500
gfs2_convert: gfs2_convert doesn't convert indirectly-pointed extended attributes correctly
When the extended attributes for a file don't fit
in one fs block, the dinode->di_eattr block becomes
an indirect block that contains pointers to blocks
that actually contain the xattrs. The gfs1 indirect
block header is different (larger) than that of gfs2
and this causes an incorrect conversion. The
resulting gfs2 filesystem cannot display the xattrs
because of leading nulls in the indirect block. This
patch adjusts this correctly.
Resolves: rhbz#576040
Signed-off-by: Abhi Das <adas(a)redhat.com>
---
gfs2/convert/gfs2_convert.c | 45 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 45 insertions(+), 0 deletions(-)
diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index 0379d33..f28aac4 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -948,6 +948,45 @@ static int fix_cdpn_symlink(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh, s
return ret;
}
+
+/*
+ * fix_xattr -
+ * Extended attributes can be either direct (in the ip->i_di.di_eattr block) or
+ * then can be at a maximum of 1 indirect level. Multiple levels of indirection
+ * are not supported. If the di_eattr block contains extended attribute data,
+ * i.e block type = GFS_METATYPE_EA, we ignore it.
+ * If the di_eattr block contains block pointers to extended attributes we need
+ * to fix the header. gfs1 uses gfs_indirect as the header which is 64 bytes
+ * bigger than gfs2_meta_header that gfs2 uses.
+ */
+static int fix_xattr(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh, struct gfs2_inode *ip)
+{
+ int ret = 0, len, old_hdr_sz, new_hdr_sz;
+ struct gfs2_buffer_head *eabh;
+ char *buf;
+
+ /* Read in the i_di.di_eattr block */
+ eabh = bread(sbp, ip->i_di.di_eattr);
+ if (!gfs2_check_meta(eabh, GFS_METATYPE_IN)) {/* if it is an indirect block */
+ len = sbp->bsize - sizeof(struct gfs_indirect);
+ buf = malloc(len);
+ if (!buf) {
+ log_crit("Error: out of memory.\n");
+ return -1;
+ }
+ old_hdr_sz = sizeof(struct gfs_indirect);
+ new_hdr_sz = sizeof(struct gfs2_meta_header);
+ memcpy(buf, eabh->b_data + old_hdr_sz, sbp->bsize - old_hdr_sz);
+ memset(eabh->b_data + new_hdr_sz, 0, sbp->bsize - new_hdr_sz);
+ memcpy(eabh->b_data + new_hdr_sz, buf, len);
+ free(buf);
+ bmodified(eabh);
+ }
+ brelse(eabh);
+
+ return ret;
+}
+
/* ------------------------------------------------------------------------- */
/* adjust_inode - change an inode from gfs1 to gfs2 */
/* */
@@ -1039,6 +1078,12 @@ static int adjust_inode(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh)
if (ret)
return -1;
}
+ /* Check for extended attributes */
+ if (inode->i_di.di_eattr) {
+ ret = fix_xattr(sbp, bh, inode);
+ if (ret)
+ return -1;
+ }
}
bmodified(inode->i_bh);
13 years, 11 months
cluster: RHEL56 - gfs2_convert: Fix conversion of gfs1 CDPNs
by Abhijith Das
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 7a9640a8e3c1c3430f5705affdc38772f0f4a1ab
Parent: df2ed5c24c9780323e8412057747c4751ef66acb
Author: Abhijith Das <adas(a)redhat.com>
AuthorDate: Fri Apr 30 10:44:22 2010 -0500
Committer: Abhijith Das <adas(a)redhat.com>
CommitterDate: Fri Apr 30 10:44:22 2010 -0500
gfs2_convert: Fix conversion of gfs1 CDPNs
GFS2 does not support Context Dependent PathNames,
so we need a way to properly convert cdpns in gfs1
to gfs2. With this patch, we replace symlinks that
point to cdpns with empty directories and adjust
the dirents in the parent directories to reflect
this.
Resolves: rhbz#573795
Signed-off-by: Abhi Das <adas(a)redhat.com>
---
gfs2/convert/gfs2_convert.c | 224 +++++++++++++++++++++++++++++++++++++------
1 files changed, 193 insertions(+), 31 deletions(-)
diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index 5f63bc4..0379d33 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -25,6 +25,7 @@
#include <string.h>
#include <time.h>
#include <sys/time.h>
+#include <errno.h>
#include "linux_endian.h"
#include <linux/types.h>
@@ -118,6 +119,12 @@ struct gfs1_sb {
char sb_reserved[96];
};
+struct inode_dir_block {
+ osi_list_t list;
+ uint64_t di_addr;
+ uint64_t di_paddr; /* Parent dir inode addr */
+};
+
struct inode_block {
osi_list_t list;
uint64_t di_addr;
@@ -135,9 +142,11 @@ struct gfs1_sb raw_gfs1_ondisk_sb;
struct gfs2_sbd sb2;
char device[256];
struct inode_block dirs_to_fix; /* linked list of directories to fix */
+struct inode_dir_block cdpns_to_fix; /* linked list of cdpn symlinks */
int seconds;
struct timeval tv;
uint64_t dirs_fixed;
+uint64_t cdpns_fixed;
uint64_t dirents_fixed;
const char *prog_name = "gfs2_convert"; /* needed by libgfs2 */
struct gfs1_jindex *sd_jindex = NULL; /* gfs1 journal index in memory */
@@ -903,6 +912,42 @@ out:
return error;
}
+const char *cdpn[14] = {"{hostname}", "{mach}", "{os}", "{uid}", "{gid}", "{sys}", "{jid}",
+ "@hostname", "@mach", "@os", "@uid", "@gid", "@sys", "@jid"};
+static int has_cdpn(const char *str)
+{
+ int i;
+ for (i=0; i<14; i++)
+ if (strstr(str, cdpn[i]) != NULL)
+ return 1;
+ return 0;
+}
+
+static int fix_cdpn_symlink(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh, struct gfs2_inode *ip)
+{
+ int ret = 0;
+ char *linkptr = NULL;
+
+ if (ip->i_di.di_height != 0)
+ return 0;
+
+ linkptr = bh->b_data + sizeof(struct gfs_dinode);
+ if (has_cdpn(linkptr)) {
+ struct inode_dir_block *fix;
+ /* Save the symlink di_addr. We'll find the parent di_addr later */
+ fix = malloc(sizeof(struct inode_dir_block));
+ if (!fix) {
+ log_crit("Error: out of memory.\n");
+ return -1;
+ }
+ memset(fix, 0, sizeof(struct inode_dir_block));
+ fix->di_addr = ip->i_di.di_num.no_addr;
+ osi_list_add_prev((osi_list_t *)&fix->list,
+ (osi_list_t *)&cdpns_to_fix);
+ }
+
+ return ret;
+}
/* ------------------------------------------------------------------------- */
/* adjust_inode - change an inode from gfs1 to gfs2 */
/* */
@@ -988,6 +1033,12 @@ static int adjust_inode(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh)
ret = adjust_indirect_blocks(sbp, inode);
if (ret)
return -1;
+ /* Check for cdpns */
+ if (inode->i_di.di_mode & S_IFLNK) {
+ ret = fix_cdpn_symlink(sbp, bh, inode);
+ if (ret)
+ return -1;
+ }
}
bmodified(inode->i_bh);
@@ -1004,7 +1055,7 @@ static int adjust_inode(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh)
/* */
/* Returns: 0 on success, -1 on failure */
/* ------------------------------------------------------------------------- */
-static int inode_renumber(struct gfs2_sbd *sbp, uint64_t root_inode_addr)
+static int inode_renumber(struct gfs2_sbd *sbp, uint64_t root_inode_addr, osi_list_t *cdpn_to_fix)
{
struct rgrp_list *rgd;
osi_list_t *tmp;
@@ -1092,13 +1143,16 @@ static int inode_renumber(struct gfs2_sbd *sbp, uint64_t root_inode_addr)
/* fetch_inum - fetch an inum entry from disk, given its block */
/* ------------------------------------------------------------------------- */
static int fetch_inum(struct gfs2_sbd *sbp, uint64_t iblock,
- struct gfs2_inum *inum)
+ struct gfs2_inum *inum, uint64_t *eablk)
{
struct gfs2_inode *fix_inode;
fix_inode = inode_read(sbp, iblock);
inum->no_formal_ino = fix_inode->i_di.di_num.no_formal_ino;
inum->no_addr = fix_inode->i_di.di_num.no_addr;
+ if (eablk)
+ *eablk = fix_inode->i_di.di_eattr;
+
inode_put(&fix_inode);
return 0;
}/* fetch_inum */
@@ -1109,12 +1163,12 @@ static int fetch_inum(struct gfs2_sbd *sbp, uint64_t iblock,
/* We changed inode numbers, so we must update that number into the */
/* directory entries themselves. */
/* */
-/* Returns: 0 on success, -1 on failure */
+/* Returns: 0 on success, -1 on failure, -EISDIR when dentmod marked DT_DIR */
/* ------------------------------------------------------------------------- */
static int process_dirent_info(struct gfs2_inode *dip, struct gfs2_sbd *sbp,
- struct gfs2_buffer_head *bh, int dir_entries)
+ struct gfs2_buffer_head *bh, int dir_entries, uint64_t dentmod)
{
- int error;
+ int error = 0;
struct gfs2_dirent *dent;
int de; /* directory entry index */
@@ -1123,12 +1177,23 @@ static int process_dirent_info(struct gfs2_inode *dip, struct gfs2_sbd *sbp,
log_crit("Error retrieving directory.\n");
return -1;
}
+ error = 0;
/* Go through every dirent in the buffer and process it. */
/* Turns out you can't trust dir_entries is correct. */
for (de = 0; ; de++) {
struct gfs2_inum inum;
int dent_was_gfs1;
-
+
+ if (dentmod) {
+ if (dent->de_type == cpu_to_be16(DT_LNK)
+ && cpu_to_be64(dent->de_inum.no_addr) == dentmod) {
+ dent->de_type = cpu_to_be16(DT_DIR);
+ error = -EISDIR;
+ break;
+ }
+ goto skip_next;
+ }
+
gettimeofday(&tv, NULL);
/* Do more warm fuzzy stuff for the customer. */
dirents_fixed++;
@@ -1142,7 +1207,7 @@ static int process_dirent_info(struct gfs2_inode *dip, struct gfs2_sbd *sbp,
gfs2_inum_in(&inum, (char *)&dent->de_inum);
dent_was_gfs1 = (dent->de_inum.no_addr == dent->de_inum.no_formal_ino);
if (inum.no_formal_ino) { /* if not a sentinel (placeholder) */
- error = fetch_inum(sbp, inum.no_addr, &inum);
+ error = fetch_inum(sbp, inum.no_addr, &inum, NULL);
if (error) {
log_crit("Error retrieving inode %" PRIx64 "\n", inum.no_addr);
break;
@@ -1185,11 +1250,30 @@ static int process_dirent_info(struct gfs2_inode *dip, struct gfs2_sbd *sbp,
break;
}
}
+ /*
+ * Compare this dirent address with every one in the
+ * cdpns_to_fix list to find if this directory (dip) is
+ * a cdpn symlink's parent. If so add it to the list element
+ */
+ if (dent->de_type == cpu_to_be16(DT_LNK)) {
+ osi_list_t *tmp;
+ struct inode_dir_block *fix;
+ osi_list_foreach(tmp, &cdpns_to_fix.list) {
+ fix = osi_list_entry(tmp, struct inode_dir_block, list);
+ if (fix->di_addr == inum.no_addr)
+ fix->di_paddr = dip->i_di.di_num.no_addr;
+ }
+ }
+
+ skip_next:
error = gfs2_dirent_next(dip, bh, &dent);
- if (error)
+ if (error) {
+ if (error == -ENOENT) /* beyond the end of this bh */
+ error = 0;
break;
+ }
} /* for every directory entry */
- return 0;
+ return error;
}/* process_dirent_info */
/* ------------------------------------------------------------------------- */
@@ -1200,7 +1284,7 @@ static int process_dirent_info(struct gfs2_inode *dip, struct gfs2_sbd *sbp,
/* */
/* Returns: 0 on success, -1 on failure */
/* ------------------------------------------------------------------------- */
-static int fix_one_directory_exhash(struct gfs2_sbd *sbp, struct gfs2_inode *dip)
+static int fix_one_directory_exhash(struct gfs2_sbd *sbp, struct gfs2_inode *dip, uint64_t dentmod)
{
struct gfs2_buffer_head *bh_leaf;
int error;
@@ -1236,13 +1320,40 @@ static int fix_one_directory_exhash(struct gfs2_sbd *sbp, struct gfs2_inode *dip
break;
}
gfs2_leaf_in(&leaf, bh_leaf); /* buffer to structure */
- error = process_dirent_info(dip, sbp, bh_leaf, leaf.lf_entries);
+ error = process_dirent_info(dip, sbp, bh_leaf, leaf.lf_entries, dentmod);
bmodified(bh_leaf);
brelse(bh_leaf);
+ if (dentmod && error == -EISDIR) /* dentmod was marked DT_DIR, break out */
+ break;
} /* for leaf_num */
return 0;
}/* fix_one_directory_exhash */
+static int process_directory(struct gfs2_sbd *sbp, uint64_t dirblock, uint64_t dentmod)
+{
+ struct gfs2_inode *dip;
+ int error = 0;
+ /* read in the directory inode */
+ dip = inode_read(sbp, dirblock);
+ /* fix the directory: either exhash (leaves) or linear (stuffed) */
+ if (dip->i_di.di_flags & GFS2_DIF_EXHASH) {
+ if (fix_one_directory_exhash(sbp, dip, dentmod)) {
+ log_crit("Error fixing exhash directory.\n");
+ inode_put(&dip);
+ return -1;
+ }
+ } else {
+ error = process_dirent_info(dip, sbp, dip->i_bh, dip->i_di.di_entries, dentmod);
+ if (error && error != -EISDIR) {
+ log_crit("Error fixing linear directory.\n");
+ inode_put(&dip);
+ return -1;
+ }
+ }
+ bmodified(dip->i_bh);
+ inode_put(&dip);
+ return 0;
+}
/* ------------------------------------------------------------------------- */
/* fix_directory_info - sync new inode numbers with directory info */
/* Returns: 0 on success, -1 on failure */
@@ -1252,7 +1363,6 @@ static int fix_directory_info(struct gfs2_sbd *sbp, osi_list_t *dir_to_fix)
osi_list_t *tmp, *fix;
struct inode_block *dir_iblk;
uint64_t offset, dirblock;
- struct gfs2_inode *dip;
dirs_fixed = 0;
dirents_fixed = 0;
@@ -1273,25 +1383,10 @@ static int fix_directory_info(struct gfs2_sbd *sbp, osi_list_t *dir_to_fix)
/* figure out the directory inode block and read it in */
dir_iblk = (struct inode_block *)fix;
dirblock = dir_iblk->di_addr; /* addr of dir inode */
- /* read in the directory inode */
- dip = inode_read(sbp, dirblock);
- /* fix the directory: either exhash (leaves) or linear (stuffed) */
- if (dip->i_di.di_flags & GFS2_DIF_EXHASH) {
- if (fix_one_directory_exhash(sbp, dip)) {
- log_crit("Error fixing exhash directory.\n");
- inode_put(&dip);
- return -1;
- }
- }
- else {
- if (process_dirent_info(dip, sbp, dip->i_bh,
- dip->i_di.di_entries)) {
- log_crit("Error fixing linear directory.\n");
- inode_put(&dip);
- return -1;
- }
+ if (process_directory(sbp, dirblock, 0)) {
+ log_crit("Error processing directory\n");
+ return -1;
}
- inode_put(&dip);
}
/* Free the last entry in memory: */
if (tmp) {
@@ -1302,6 +1397,60 @@ static int fix_directory_info(struct gfs2_sbd *sbp, osi_list_t *dir_to_fix)
}/* fix_directory_info */
/* ------------------------------------------------------------------------- */
+/* fix_cdpn_symlinks - convert cdpn symlinks to empty directories */
+/* Returns: 0 on success, -1 on failure */
+/* ------------------------------------------------------------------------- */
+static int fix_cdpn_symlinks(struct gfs2_sbd *sbp, osi_list_t *cdpn_to_fix)
+{
+ osi_list_t *tmp, *x;
+ int error = 0;
+
+ cdpns_fixed = 0;
+ osi_list_foreach_safe(tmp, cdpn_to_fix, x) {
+ struct gfs2_inum fix, dir;
+ struct inode_dir_block *l_fix;
+ struct gfs2_buffer_head *bh;
+ struct gfs2_inode *fix_inode;
+ uint64_t eablk;
+
+ l_fix = osi_list_entry(tmp, struct inode_dir_block, list);
+ osi_list_del(tmp);
+
+ /* convert symlink to empty dir */
+ error = fetch_inum(sbp, l_fix->di_addr, &fix, &eablk);
+ if (error) {
+ log_crit("Error retrieving inode at block %llx\n",
+ (unsigned long long)l_fix->di_addr);
+ break;
+ }
+ error = fetch_inum(sbp, l_fix->di_paddr, &dir, NULL);
+ if (error) {
+ log_crit("Error retrieving inode at block %llx\n",
+ (unsigned long long)l_fix->di_paddr);
+ break;
+ }
+
+ /* initialize the symlink inode to be a directory */
+ bh = init_dinode(sbp, &fix, S_IFDIR | 0755, 0, &dir);
+ fix_inode = inode_get(sbp, bh);
+ fix_inode->i_di.di_eattr = eablk; /*fix extended attribute */
+ inode_put(&fix_inode);
+ bmodified(bh);
+ brelse(bh);
+
+ /* fix the parent directory dirent entry for this inode */
+ error = process_directory(sbp, l_fix->di_paddr, l_fix->di_addr);
+ if (error) {
+ log_crit("Error trying to fix cdpn dentry\n");
+ break;
+ }
+ free(l_fix);
+ cdpns_fixed++;
+ }
+ return error;
+} /* fix_cdpn_symlinks */
+
+/* ------------------------------------------------------------------------- */
/* Fetch gfs1 jindex structure from buffer */
/* ------------------------------------------------------------------------- */
static void gfs1_jindex_in(struct gfs1_jindex *jindex, char *buf)
@@ -1399,6 +1548,7 @@ static int init(struct gfs2_sbd *sbp)
sbp->sd_sb.sb_header.mh_format = GFS2_FORMAT_SB;
osi_list_init((osi_list_t *)&dirs_to_fix);
+ osi_list_init((osi_list_t *)&cdpns_to_fix);
/* ---------------------------------------------- */
/* Initialize lists and read in the superblock. */
/* ---------------------------------------------- */
@@ -1857,7 +2007,8 @@ int main(int argc, char **argv)
/* Renumber the inodes consecutively. */
/* ---------------------------------------------- */
if (!error) {
- error = inode_renumber(&sb2, sb2.sd_sb.sb_root_dir.no_addr);
+ error = inode_renumber(&sb2, sb2.sd_sb.sb_root_dir.no_addr,
+ (osi_list_t *)&cdpns_to_fix);
if (error)
log_crit("\n%s: Error renumbering inodes.\n", device);
fsync(sb2.device_fd); /* write the buffers to disk */
@@ -1874,6 +2025,17 @@ int main(int argc, char **argv)
log_crit("\n%s: Error fixing directories.\n", device);
}
/* ---------------------------------------------- */
+ /* Convert cdpn symlinks to empty dirs */
+ /* ---------------------------------------------- */
+ if (!error) {
+ error = fix_cdpn_symlinks(&sb2, (osi_list_t *)&cdpns_to_fix);
+ log_notice("\r%" PRIu64 " cdpn symlinks moved to empty directories.",
+ cdpns_fixed);
+ fflush(stdout);
+ if (error)
+ log_crit("\n%s: Error fixing cdpn symlinks.\n", device);
+ }
+ /* ---------------------------------------------- */
/* Convert journal space to rg space */
/* ---------------------------------------------- */
if (!error) {
13 years, 11 months
cluster: RHEL56 - gfs2_convert: gfs2_convert uses too much memory for jdata conversion
by Abhijith Das
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: df2ed5c24c9780323e8412057747c4751ef66acb
Parent: e16c5e55e999c8f928c398a7afc7f100063d0c7f
Author: Abhijith Das <adas(a)redhat.com>
AuthorDate: Fri Apr 30 10:42:03 2010 -0500
Committer: Abhijith Das <adas(a)redhat.com>
CommitterDate: Fri Apr 30 10:42:03 2010 -0500
gfs2_convert: gfs2_convert uses too much memory for jdata conversion
Moved some code around so that the data blocks of the
jdata file are not mapped into buffers in advance.
Instead, only indirect blocks one level below are mapped.
The data blocks are then mapped one-by-one while they're
copied onto the new converted jdata file.
Resolves: rhbz#571876
Signed-off-by: Abhi Das <adas(a)redhat.com>
---
gfs2/convert/gfs2_convert.c | 105 +++++++++++++++++++++++++++++-------------
gfs2/libgfs2/fs_ops.c | 1 +
2 files changed, 73 insertions(+), 33 deletions(-)
diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index 5a45c96..5f63bc4 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -322,8 +322,7 @@ static void fix_metatree(struct gfs2_sbd *sbp, struct gfs2_inode *ip,
bh = ip->i_bh;
/* First, build up the metatree */
for (h = 0; h < blk->height; h++) {
- lookup_block(ip, ip->i_bh, h, &blk->mp, 1, &new,
- &block);
+ lookup_block(ip, bh, h, &blk->mp, 1, &new, &block);
if (bh != ip->i_bh)
brelse(bh);
if (!block)
@@ -674,6 +673,7 @@ void fix_jdatatree(struct gfs2_sbd *sbp, struct gfs2_inode *ip,
memcpy(bh->b_data + ptramt,
(char *)srcptr, amount);
srcptr += amount;
+ bmodified(bh);
if (bh != ip->i_bh)
brelse(bh);
@@ -748,16 +748,14 @@ int adjust_jdata_inode(struct gfs2_sbd *sbp, struct gfs2_inode *ip)
sbp->bsize - sizeof(struct gfs_dinode));
osi_list_add_prev(&blk->list, &blocks.list);
- /* Now run the metadata chain and build lists of all data/metadata blocks */
+ /* Now run the metadata chain and build lists of all metadata blocks */
osi_list_foreach(tmp, &blocks.list) {
blk = osi_list_entry(tmp, struct blocklist, list);
- if (blk->height >= ip->i_di.di_height)
+ if (blk->height >= ip->i_di.di_height - 1)
continue;
-
header_size = (blk->height > 0 ? sizeof(struct gfs_indirect) :
sizeof(struct gfs_dinode));
-
for (ptr1 = (uint64_t *)blk->ptrbuf, ptrnum = 0;
ptrnum < sbp->sd_inptrs; ptr1++, ptrnum++) {
if (!*ptr1)
@@ -790,23 +788,14 @@ int adjust_jdata_inode(struct gfs2_sbd *sbp, struct gfs2_inode *ip)
/* Queue it to be processed later on in the loop. */
osi_list_add_prev(&newblk->list, &blocks.list);
+ /* read the new metadata block's pointers */
bh = bread(sbp, block);
- if (newblk->height == ip->i_di.di_height) {
- /* read in the jdata block */
- memcpy(newblk->ptrbuf, bh->b_data +
- sizeof(struct gfs2_meta_header), bufsize);
- /* Zero the buffer so we can fill it in later */
- memset(bh->b_data + sizeof(struct gfs2_meta_header), 0,
- bufsize);
- } else {
- /* read the new metadata block's pointers */
- memcpy(newblk->ptrbuf, bh->b_data +
- sizeof(struct gfs_indirect),
- sbp->bsize - sizeof(struct gfs_indirect));
- /* Zero the buffer so we can fill it in later */
- memset(bh->b_data + sizeof(struct gfs_indirect), 0,
- sbp->bsize - sizeof(struct gfs_indirect));
- }
+ memcpy(newblk->ptrbuf, bh->b_data + sizeof(struct gfs_indirect),
+ sbp->bsize - sizeof(struct gfs_indirect));
+ /* Zero the buffer so we can fill it in later */
+ memset(bh->b_data + sizeof(struct gfs_indirect), 0,
+ sbp->bsize - sizeof(struct gfs_indirect));
+ bmodified(bh);
brelse(bh);
/* Free the block so we can reuse it. This allows us to
convert a "full" file system. */
@@ -831,18 +820,68 @@ int adjust_jdata_inode(struct gfs2_sbd *sbp, struct gfs2_inode *ip)
blk = osi_list_entry(tmp, struct blocklist, list);
/* If it's not a data block at the highest level */
- if (blk->height != di_height) {
+ if (blk->height != di_height - 1) {
osi_list_del(tmp);
free(blk->ptrbuf);
free(blk);
continue;
}
- len = bufsize;
- jdata_mp_gfs1_to_gfs2(sbp, di_height, gfs2_hgt, &blk->mp, &gfs2mp, &len, dinode_size);
- memcpy(&blk->mp, &gfs2mp, sizeof(struct metapath));
- blk->height -= di_height - gfs2_hgt;
- if (len)
- fix_jdatatree(sbp, ip, blk, blk->ptrbuf, len);
+ /*
+ * For each metadata block that holds jdata block pointers,
+ * get the blk pointers and copy them block by block
+ */
+ for (ptr1 = (uint64_t *) blk->ptrbuf, ptrnum = 0;
+ ptrnum < sbp->sd_inptrs; ptr1++, ptrnum++) {
+ if (!*ptr1)
+ continue;
+ block = be64_to_cpu(*ptr1);
+
+ newblk = malloc(sizeof(struct blocklist));
+ if (!newblk) {
+ log_crit("Error: Can't allocate memory"
+ " for indirect block fix.\n");
+ error = -1;
+ goto out;
+ }
+ memset(newblk, 0, sizeof(*newblk));
+ newblk->ptrbuf = malloc(bufsize);
+ if (!newblk->ptrbuf) {
+ log_crit("Error: Can't allocate memory"
+ " for file conversion.\n");
+ free(newblk);
+ goto out;
+ }
+ memset(newblk->ptrbuf, 0, bufsize);
+ newblk->block = block;
+ newblk->height = blk->height + 1;
+ /* Build the metapointer list from our predecessors */
+ for (h=0; h < blk->height; h++)
+ newblk->mp.mp_list[h] = blk->mp.mp_list[h];
+ newblk->mp.mp_list[h] = ptrnum;
+ bh = bread(sbp, block);
+ /* This is a data block. i.e newblk->height == ip->i_di.di_height */
+ /* read in the jdata block */
+ memcpy(newblk->ptrbuf, bh->b_data +
+ sizeof(struct gfs2_meta_header), bufsize);
+ memset(bh->b_data + sizeof(struct gfs2_meta_header), 0,
+ bufsize);
+ bmodified(bh);
+ brelse(bh);
+ /* Free the block so we can reuse it. This allows us to
+ convert a "full" file system */
+ ip->i_di.di_blocks--;
+ gfs2_free_block(sbp, block);
+
+ len = bufsize;
+ jdata_mp_gfs1_to_gfs2(sbp, di_height, gfs2_hgt, &newblk->mp, &gfs2mp,
+ &len, dinode_size);
+ memcpy(&newblk->mp, &gfs2mp, sizeof(struct metapath));
+ newblk->height -= di_height - gfs2_hgt;
+ if (len)
+ fix_jdatatree(sbp, ip, newblk, newblk->ptrbuf, len);
+ free(newblk->ptrbuf);
+ free(newblk);
+ }
osi_list_del(tmp);
free(blk->ptrbuf);
free(blk);
@@ -942,10 +981,10 @@ static int adjust_inode(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh)
inode->i_di.di_goal_data = 0; /* make sure the upper 32b are 0 */
inode->i_di.di_goal_data = gfs1_dinode_struct->di_goal_dblk;
inode->i_di.di_generation = 0;
- if (!(inode->i_di.di_mode & S_IFDIR) &&
+ if (!(inode->i_di.di_mode & S_IFDIR) &&
inode->i_di.di_flags & GFS2_DIF_JDATA)
ret = adjust_jdata_inode(sbp, inode);
- else
+ else
ret = adjust_indirect_blocks(sbp, inode);
if (ret)
return -1;
@@ -1011,9 +1050,9 @@ static int inode_renumber(struct gfs2_sbd *sbp, uint64_t root_inode_addr)
sbp->sd_sb.sb_root_dir.no_formal_ino = sbp->md.next_inum;
}
bh = bread(sbp, block);
- if (!gfs2_check_meta(bh, GFS_METATYPE_DI)) /* if it is an dinode */
+ if (!gfs2_check_meta(bh, GFS_METATYPE_DI)) {/* if it is an dinode */
error = adjust_inode(sbp, bh);
- else { /* It's metadata, but not an inode, so fix the bitmap. */
+ } else { /* It's metadata, but not an inode, so fix the bitmap. */
int blk, buf_offset;
int bitmap_byte; /* byte within the bitmap to fix */
int byte_bit; /* bit within the byte */
diff --git a/gfs2/libgfs2/fs_ops.c b/gfs2/libgfs2/fs_ops.c
index aed34c6..9aeeb23 100644
--- a/gfs2/libgfs2/fs_ops.c
+++ b/gfs2/libgfs2/fs_ops.c
@@ -931,6 +931,7 @@ static void dir_split_leaf(struct gfs2_inode *dip, uint32_t lindex,
dip->i_di.di_blocks++;
bmodified(dip->i_bh);
+ bmodified(obh); /* Need to do this in case nothing was moved */
brelse(obh);
bmodified(nbh);
brelse(nbh);
13 years, 11 months
cluster: RHEL56 - gfs2_convert: gfs2_convert segfaults when converting filesystems of blocksize 512 bytes
by Abhijith Das
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: e16c5e55e999c8f928c398a7afc7f100063d0c7f
Parent: d97b163ff014f1096a32afc908643dfb8dd396ff
Author: Abhijith Das <adas(a)redhat.com>
AuthorDate: Thu Apr 29 21:26:05 2010 -0500
Committer: Abhijith Das <adas(a)redhat.com>
CommitterDate: Thu Apr 29 21:26:05 2010 -0500
gfs2_convert: gfs2_convert segfaults when converting filesystems of blocksize 512 bytes
gfs2_convert segfaults when the jindex inode is unstuffed.
i.e. if the block size is small enough such that the jindex
entries (directly proportional to the number of journals)
don't fit in the disk inode block, the jindex inode is
unstuffed. This is a journaled data file and the structures
are different for such files in gfs1 and gfs2 with respect
to metaheaders. gfs2_convert needs to trick the file
reading code in libgfs2 to think it's dealing with a gfs2
directory (whose structure is similar to a gfs1 jdata inode)
to operate on the file at the right offsets.
Resolves: rhbz#568852
Signed-off-by: Abhi Das <adas(a)redhat.com>
---
gfs2/convert/gfs2_convert.c | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index 3a9905e..5a45c96 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -1284,6 +1284,7 @@ static int read_gfs1_jiindex(struct gfs2_sbd *sdp)
char buf[sizeof(struct gfs1_jindex)];
unsigned int j;
int error=0;
+ unsigned int tmp_mode = 0;
if(ip->i_di.di_size % sizeof(struct gfs1_jindex) != 0){
log_crit("The size reported in the journal index"
@@ -1299,6 +1300,14 @@ static int read_gfs1_jiindex(struct gfs2_sbd *sdp)
log_crit("Unable to zero journal index\n");
return -1;
}
+ /* ugly hack
+ * Faking the gfs1_jindex inode as a directory to gfs2_readi
+ * so it skips the metaheader struct in the data blocks
+ * in the inode. gfs2_jindex inode doesn't have metaheaders
+ * in the data blocks */
+ tmp_mode = ip->i_di.di_mode;
+ ip->i_di.di_mode &= ~S_IFMT;
+ ip->i_di.di_mode |= S_IFDIR;
for (j = 0; ; j++) {
struct gfs1_jindex *journ;
@@ -1315,6 +1324,7 @@ static int read_gfs1_jiindex(struct gfs2_sbd *sdp)
gfs1_jindex_in(journ, buf);
sdp->jsize = (journ->ji_nsegment * 16 * sdp->bsize) >> 20;
}
+ ip->i_di.di_mode = tmp_mode;
if(j * sizeof(struct gfs1_jindex) != ip->i_di.di_size){
log_crit("journal inode size invalid\n");
goto fail;
13 years, 11 months
cluster: RHEL56 - gfs_jadd: gfs_jadd does not resolve symbolic links
by Abhijith Das
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: d97b163ff014f1096a32afc908643dfb8dd396ff
Parent: 4b4ac43455ebfe95aac903fdd4c67a8a09e4e180
Author: Abhijith Das <adas(a)redhat.com>
AuthorDate: Thu Apr 29 21:10:45 2010 -0500
Committer: Abhijith Das <adas(a)redhat.com>
CommitterDate: Thu Apr 29 21:10:45 2010 -0500
gfs_jadd: gfs_jadd does not resolve symbolic links
This patch resolves symbolic links for the device name.
Resolves: rhbz# 555363
Signed-off-by: Abhi Das <adas(a)redhat.com>
---
gfs/gfs_jadd/main.c | 15 ++++++++++++---
1 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/gfs/gfs_jadd/main.c b/gfs/gfs_jadd/main.c
index ead625b..6bdd9fc 100644
--- a/gfs/gfs_jadd/main.c
+++ b/gfs/gfs_jadd/main.c
@@ -715,33 +715,42 @@ update_fs(void)
*/
static int
-find_fs(char *name)
+find_fs(const char *name)
{
FILE *fp = fopen("/proc/mounts", "r");
char buffer[4096];
char fstype[80];
int fsdump, fspass;
+ char *realname;
+ realname = realpath(name, NULL);
+ if (!realname) {
+ perror(name);
+ return -1;
+ }
if (fp == NULL) {
perror("open: /proc/mounts");
exit(EXIT_FAILURE);
}
while ((fgets(buffer, 4095, fp)) != NULL) {
buffer[4095] = 0;
- if (strstr(buffer, name) == 0)
+ if (strstr(buffer, realname) == 0)
continue;
if (sscanf(buffer, "%s %s %s %s %d %d", device, fspath, fstype,
fsoptions, &fsdump, &fspass) != 6)
continue;
if (strcmp(fstype, "gfs") != 0)
continue;
- if ((strcmp(device, name) != 0) && (strcmp(fspath, name) != 0))
+ if ((strcmp(device, realname) != 0) &&
+ (strcmp(fspath, realname) != 0))
continue;
fclose(fp);
+ free(realname);
return 0;
}
fprintf(stderr, "GFS Filesystem %s not found\n", name);
fclose(fp);
+ free(realname);
return 1;
}
13 years, 11 months
cluster: RHEL55 - HA LVM: Use CLVM with local machine kernel targets (bz 585229)
by Jonathan Brassow
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 7804e516b06c77cdfb3d5a969018cee6b05b5003
Parent: fee7b0d92edb3ed99bdbd6194b72103c22279e94
Author: Jonathan Brassow <jbrassow(a)redhat.com>
AuthorDate: Thu Apr 29 14:07:04 2010 -0500
Committer: Jonathan Brassow <jbrassow(a)redhat.com>
CommitterDate: Thu Apr 29 14:07:04 2010 -0500
HA LVM: Use CLVM with local machine kernel targets (bz 585229)
When a logical volume is activated in a cluster exclusively,
the kernel targets used are single machine targets. This
means we can use CLVM to protect the LVM metadata and still
better align ourselves with active/passive application stacks.
Making this change also simplifies HA LVM setup. There is no
more setting up tags, volume_list entries, or updating the
initrd.
Updating HA-LVM in this way also addresses the following bugs:
- 509368
- 583769
- 572311
---
rgmanager/src/resources/lvm.sh | 52 ++-----------
rgmanager/src/resources/lvm_by_lv.sh | 75 +++++++++++++++++-
rgmanager/src/resources/lvm_by_vg.sh | 147 +++++++++++++++++++++++++++++++++-
3 files changed, 221 insertions(+), 53 deletions(-)
diff --git a/rgmanager/src/resources/lvm.sh b/rgmanager/src/resources/lvm.sh
index ffb0b21..a972aaf 100755
--- a/rgmanager/src/resources/lvm.sh
+++ b/rgmanager/src/resources/lvm.sh
@@ -36,19 +36,6 @@ export LC_ALL LANG PATH
rv=0
################################################################################
-# clvm_check
-#
-################################################################################
-function clvm_check
-{
- if [[ $(vgs -o attr --noheadings $1) =~ .....c ]]; then
- return 1
- fi
-
- return 0
-}
-
-################################################################################
# ha_lvm_proper_setup_check
#
################################################################################
@@ -106,18 +93,10 @@ function ha_lvm_proper_setup_check
case $1 in
start)
- ##
- # We can safely ignore clustered volume groups (VGs handled by CLVM)
- ##
- if ! clvm_check $OCF_RESKEY_vg_name; then
- ocf_log notice "$OCF_RESKEY_vg_name is a cluster volume. Ignoring..."
- exit 0
+ if ! [[ $(vgs -o attr --noheadings $OCF_RESKEY_vg_name) =~ .....c ]]; then
+ ha_lvm_proper_setup_check || exit 1
fi
- ha_lvm_proper_setup_check || exit 1
-
- rv=0
-
if [ -z $OCF_RESKEY_lv_name ]; then
vg_start || exit 1
else
@@ -133,20 +112,13 @@ status|monitor)
else
lv_status || exit 1
fi
- rv=0
;;
stop)
- ##
- # We can safely ignore clustered volume groups (VGs handled by CLVM)
- ##
- if ! clvm_check $OCF_RESKEY_vg_name; then
- ocf_log notice "$OCF_RESKEY_vg_name is a cluster volume. Ignoring..."
- exit 0
- fi
-
- if ! ha_lvm_proper_setup_check; then
- ocf_log err "WARNING: An improper setup can cause data corruption!"
+ if ! [[ $(vgs -o attr --noheadings $OCF_RESKEY_vg_name) =~ .....c ]]; then
+ if ! ha_lvm_proper_setup_check; then
+ ocf_log err "WARNING: An improper setup can cause data corruption!"
+ fi
fi
if [ -z $OCF_RESKEY_lv_name ]; then
@@ -154,35 +126,23 @@ stop)
else
lv_stop || exit 1
fi
- rv=0
;;
recover|restart)
$0 stop || exit $OCF_ERR_GENERIC
$0 start || exit $OCF_ERR_GENERIC
- rv=0
;;
meta-data)
cat `echo $0 | sed 's/^\(.*\)\.sh$/\1.metadata/'`
- rv=0
;;
validate-all|verify-all)
- ##
- # We can safely ignore clustered volume groups (VGs handled by CLVM)
- ##
- if ! clvm_check $OCF_RESKEY_vg_name; then
- ocf_log notice "$OCF_RESKEY_vg_name is a cluster volume. Ignoring..."
- exit 0
- fi
-
if [ -z $OCF_RESKEY_lv_name ]; then
vg_verify || exit 1
else
lv_verify || exit 1
fi
- rv=0
;;
*)
echo "usage: $0 {start|status|monitor|stop|restart|meta-data|verify-all}"
diff --git a/rgmanager/src/resources/lvm_by_lv.sh b/rgmanager/src/resources/lvm_by_lv.sh
index 1937b9f..da15a15 100644
--- a/rgmanager/src/resources/lvm_by_lv.sh
+++ b/rgmanager/src/resources/lvm_by_lv.sh
@@ -101,10 +101,22 @@ lv_activate_resilient()
fi
}
+lv_status_clustered()
+{
+ #
+ # Check if device is active
+ #
+ if [[ ! $(lvs -o attr --noheadings $lv_path) =~ ....a. ]]; then
+ return $OCF_ERR_GENERIC
+ fi
+
+ return $OCF_SUCCESS
+}
+
# lv_status
#
# Is the LV active?
-lv_status()
+lv_status_single()
{
declare lv_path="$OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name"
declare dev="/dev/$lv_path"
@@ -167,6 +179,16 @@ lv_status()
return $OCF_SUCCESS
}
+function lv_status
+{
+ # We pass in the VG name to see of the logical volume is clustered
+ if [[ $(vgs -o attr --noheadings $OCF_RESKEY_vg_name) =~ .....c ]]; then
+ lv_status_clustered
+ else
+ lv_status_single
+ fi
+}
+
# lv_activate_and_tag
lv_activate_and_tag()
{
@@ -334,7 +356,29 @@ lv_activate()
return $OCF_SUCCESS
}
-function lv_start
+function lv_start_clustered
+{
+ if ! lvchange -aey $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name; then
+ ocf_log err "Failed to activate logical volume, $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name"
+ ocf_log notice "Attempting cleanup of $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name"
+
+ if ! lvconvert --repair --use-policies $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name; then
+ ocf_log err "Failed to cleanup $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name"
+ return $OCF_ERR_GENERIC
+ fi
+
+ if ! lvchange -aey $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name; then
+ ocf_log err "Failed second attempt to activate $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name"
+ return $OCF_ERR_GENERIC
+ fi
+
+ ocf_log notice "Second attempt to activate $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name successful"
+ return $OCF_SUCCESS
+ fi
+ return $OCF_SUCCESS
+}
+
+function lv_start_single
{
if ! lvs $OCF_RESKEY_vg_name >& /dev/null; then
lv_count=0
@@ -355,7 +399,22 @@ function lv_start
return 0
}
-function lv_stop
+function lv_start
+{
+ # We pass in the VG name to see of the logical volume is clustered
+ if [[ $(vgs -o attr --noheadings $OCF_RESKEY_vg_name) =~ .....c ]]; then
+ lv_start_clustered
+ else
+ lv_start_single
+ fi
+}
+
+function lv_stop_clustered
+{
+ lvchange -aln $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name
+}
+
+function lv_stop_single
{
if ! lv_activate stop; then
return 1
@@ -363,3 +422,13 @@ function lv_stop
return 0
}
+
+function lv_stop
+{
+ # We pass in the VG name to see of the logical volume is clustered
+ if [[ $(vgs -o attr --noheadings $OCF_RESKEY_vg_name) =~ .....c ]]; then
+ lv_stop_clustered
+ else
+ lv_stop_single
+ fi
+}
diff --git a/rgmanager/src/resources/lvm_by_vg.sh b/rgmanager/src/resources/lvm_by_vg.sh
index 014dcbf..08d8c98 100755
--- a/rgmanager/src/resources/lvm_by_vg.sh
+++ b/rgmanager/src/resources/lvm_by_vg.sh
@@ -85,14 +85,18 @@ function strip_and_add_tag
return $OCF_SUCCESS
}
+function vg_status_clustered
+{
+ return $OCF_SUCCESS
+}
+
# vg_status
#
# Are all the LVs active?
-function vg_status
+function vg_status_single
{
local i
local dev
- local readdev
local my_name=$(local_node_name)
#
@@ -144,13 +148,88 @@ function vg_status
return $OCF_SUCCESS
}
+##
+# Main status function for volume groups
+##
+function vg_status
+{
+ if [[ $(vgs -o attr --noheadings $OCF_RESKEY_vg_name) =~ .....c ]]; then
+ vg_status_clustered
+ else
+ vg_status_single
+ fi
+}
+
function vg_verify
{
# Anything to verify?
return $OCF_SUCCESS
}
-function vg_start
+function vg_start_clustered
+{
+ local a
+ local results
+ local all_pvs
+ local resilience
+
+ ocf_log info "Starting volume group, $OCF_RESKEY_vg_name"
+
+ if ! vgchange -aey $OCF_RESKEY_vg_name; then
+ ocf_log err "Failed to activate volume group, $OCF_RESKEY_vg_name"
+ ocf_log notice "Attempting cleanup of $OCF_RESKEY_vg_name"
+
+ if ! vgreduce --removemissing $OCF_RESKEY_vg_name; then
+ ocf_log err "Failed to make $OCF_RESKEY_vg_name consistent"
+ return $OCF_ERR_GENERIC
+ fi
+
+ if ! vgchange -aey $OCF_RESKEY_vg_name; then
+ ocf_log err "Failed second attempt to activate $OCF_RESKEY_vg_name"
+ return $OCF_ERR_GENERIC
+ fi
+
+ ocf_log notice "Second attempt to activate $OCF_RESKEY_vg_name successful"
+ return $OCF_SUCCESS
+ else
+ # The activation commands succeeded, but did they do anything?
+ # Make sure all the logical volumes are active
+ results=(`lvs -o name,attr --noheadings 2> /dev/null $OCF_RESKEY_vg_name`)
+ a=0
+ while [ ! -z ${results[$a]} ]; do
+ if [[ ! ${results[$(($a + 1))]} =~ ....a. ]]; then
+ all_pvs=(`pvs --noheadings -o name 2> /dev/null`)
+ resilience=" --config devices{filter=["
+ for i in ${all_pvs[*]}; do
+ resilience=$resilience'"a|'$i'|",'
+ done
+ resilience=$resilience"\"r|.*|\"]}"
+
+ vgchange -aey $OCF_RESKEY_vg_name $resilience
+ break
+ fi
+ a=$(($a + 2))
+ done
+
+ # We need to check the LVs again if we made the command resilient
+ if [ ! -z $resilience ]; then
+ results=(`lvs -o name,attr --noheadings $OCF_RESKEY_vg_name $resilience 2> /dev/null`)
+ a=0
+ while [ ! -z ${results[$a]} ]; do
+ if [[ ! ${results[$(($a + 1))]} =~ ....a. ]]; then
+ ocf_log err "Failed to activate $OCF_RESKEY_vg_name"
+ return $OCF_ERR_GENERIC
+ fi
+ a=$(($a + 2))
+ done
+ ocf_log err "Orphan storage device in $OCF_RESKEY_vg_name slowing operations"
+ fi
+ fi
+
+ return $OCF_SUCCESS
+}
+
+function vg_start_single
{
local a
local results
@@ -238,7 +317,55 @@ function vg_start
return $OCF_SUCCESS
}
-function vg_stop
+##
+# Main start function for volume groups
+##
+function vg_start
+{
+ if [[ $(vgs -o attr --noheadings $OCF_RESKEY_vg_name) =~ .....c ]]; then
+ vg_start_clustered
+ else
+ vg_start_single
+ fi
+}
+
+function vg_stop_clustered
+{
+ local a
+ local results
+ typeset self_fence=""
+
+ case ${OCF_RESKEY_self_fence} in
+ "yes") self_fence=1 ;;
+ 1) self_fence=1 ;;
+ *) self_fence="" ;;
+ esac
+
+ # Shut down the volume group
+ # Do we need to make this resilient?
+ vgchange -aln $OCF_RESKEY_vg_name
+
+ # Make sure all the logical volumes are inactive
+ results=(`lvs -o name,attr --noheadings $OCF_RESKEY_vg_name 2> /dev/null`)
+ a=0
+ while [ ! -z ${results[$a]} ]; do
+ if [[ ${results[$(($a + 1))]} =~ ....a. ]]; then
+ if [ "$self_fence" ]; then
+ ocf_log err "Unable to deactivate $lv_path REBOOT"
+ sync
+ reboot -fn
+ else
+ ocf_log err "Logical volume $OCF_RESKEY_vg_name/${results[$a]} failed to shutdown"
+ fi
+ return $OCF_ERR_GENERIC
+ fi
+ a=$(($a + 2))
+ done
+
+ return $OCF_SUCCESS
+}
+
+function vg_stop_single
{
local a
local results
@@ -279,3 +406,15 @@ function vg_stop
return $OCF_SUCCESS
}
+
+##
+# Main stop function for volume groups
+##
+function vg_stop
+{
+ if [[ $(vgs -o attr --noheadings $OCF_RESKEY_vg_name) =~ .....c ]]; then
+ vg_stop_clustered
+ else
+ vg_stop_single
+ fi
+}
13 years, 11 months
cluster: STABLE3 - cman: fix name of fail_recv_const
by Christine Caulfield
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 4a66dd6aa8e60fc03b027c1fbdbfd37681878954
Parent: 6d250e9c15576aa1da9154b2581911cbd3ce394e
Author: Christine Caulfield <ccaulfie(a)redhat.com>
AuthorDate: Thu Apr 29 16:28:13 2010 +0100
Committer: Christine Caulfield <ccaulfie(a)redhat.com>
CommitterDate: Thu Apr 29 16:28:13 2010 +0100
cman: fix name of fail_recv_const
Signed-off-by: Christine Caulfield <ccaulfie(a)redhat.com>
---
cman/daemon/cman-preconfig.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/cman/daemon/cman-preconfig.c b/cman/daemon/cman-preconfig.c
index 3582162..ef5964f 100644
--- a/cman/daemon/cman-preconfig.c
+++ b/cman/daemon/cman-preconfig.c
@@ -702,8 +702,8 @@ static void add_cman_overrides(struct objdb_iface_ver0 *objdb)
"60", strlen("60")+1, OBJDB_VALUETYPE_STRING);
}
/* Extend fail_to_recv_const, see bz#587078 */
- if (objdb_get_string(objdb, object_handle, "fail_to_recv_const", &value)) {
- objdb->object_key_create_typed(object_handle, "fail_to_recv_const",
+ if (objdb_get_string(objdb, object_handle, "fail_recv_const", &value)) {
+ objdb->object_key_create_typed(object_handle, "fail_recv_const",
"2500", strlen("2500")+1, OBJDB_VALUETYPE_STRING);
}
/* consensus should be 2*token, see bz#544482*/
13 years, 11 months
cluster: STABLE3 - Make totem.fail_to_recv_const default to 2500
by Christine Caulfield
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 6d250e9c15576aa1da9154b2581911cbd3ce394e
Parent: 077861319e8a8a7b08ae7599738cab50ba341744
Author: Christine Caulfield <ccaulfie(a)redhat.com>
AuthorDate: Thu Apr 29 10:00:13 2010 +0100
Committer: Christine Caulfield <ccaulfie(a)redhat.com>
CommitterDate: Thu Apr 29 10:00:13 2010 +0100
Make totem.fail_to_recv_const default to 2500
bz#587082
Signed-off-by: Christine Caulfield <ccaulfie(a)redhat.com>
---
cman/daemon/cman-preconfig.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/cman/daemon/cman-preconfig.c b/cman/daemon/cman-preconfig.c
index e8248b4..3582162 100644
--- a/cman/daemon/cman-preconfig.c
+++ b/cman/daemon/cman-preconfig.c
@@ -701,6 +701,11 @@ static void add_cman_overrides(struct objdb_iface_ver0 *objdb)
objdb->object_key_create_typed(object_handle, "join",
"60", strlen("60")+1, OBJDB_VALUETYPE_STRING);
}
+ /* Extend fail_to_recv_const, see bz#587078 */
+ if (objdb_get_string(objdb, object_handle, "fail_to_recv_const", &value)) {
+ objdb->object_key_create_typed(object_handle, "fail_to_recv_const",
+ "2500", strlen("2500")+1, OBJDB_VALUETYPE_STRING);
+ }
/* consensus should be 2*token, see bz#544482*/
if (objdb_get_string(objdb, object_handle, "consensus", &value)) {
unsigned int token;
13 years, 11 months