X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;ds=sidebyside;f=lustre%2Futils%2Flustre_rsync.c;h=1b7b52f0eb9f972efa6130c2a318643bca6eaae9;hb=9abdf96e56e239b81102c8a43dc2f0524f2be90a;hp=113dc04f09104c61347b6b7b647d37d1ae4f1305;hpb=e0d2bfe3b93d5179c9aee4a65e1695fa4c7779ed;p=fs%2Flustre-release.git diff --git a/lustre/utils/lustre_rsync.c b/lustre/utils/lustre_rsync.c index 113dc04..1b7b52f 100644 --- a/lustre/utils/lustre_rsync.c +++ b/lustre/utils/lustre_rsync.c @@ -15,11 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ @@ -27,7 +23,7 @@ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. * - * Copyright (c) 2012, Intel Corporation. + * Copyright (c) 2012, 2017, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ @@ -107,6 +103,7 @@ * [pfid,tfid,name] tracked from (1) is used for this. */ +#include #include #include #include @@ -114,17 +111,20 @@ #include #include #include +#include #include #include #include #include #include +#include #include +#include -#include +#include #include -#include #include "lustre_rsync.h" +#include "callvpe.h" #define REPLICATE_STATUS_VER 1 #define CLEAR_INTERVAL 100 @@ -141,10 +141,6 @@ #define DINFO 1 #define DTRACE 2 -/* Not used; declared for fulfilling obd.c's dependency. */ -command_t cmdlist[0]; -extern int obd_initialize(int argc, char **argv); - /* Information for processing a changelog record. This structure is allocated on the heap instead of allocating large variables on the stack. */ @@ -159,13 +155,12 @@ struct lr_info { char spfid[LR_FID_STR_LEN]; char sname[NAME_MAX + 1]; char name[NAME_MAX + 1]; - char src[PATH_MAX + 1]; - char dest[PATH_MAX + 1]; + char src[3 * PATH_MAX + 1]; + char dest[3 * PATH_MAX + 1]; char path[PATH_MAX + 1]; char savedpath[PATH_MAX + 1]; char link[PATH_MAX + 1]; char linktmp[PATH_MAX + 1]; - char cmd[PATH_MAX]; int bufsize; char *buf; @@ -197,32 +192,32 @@ int quit; /* Flag to stop processing the changelog; set on the receipt of a signal */ int abort_on_err = 0; -char rsync[PATH_MAX]; -char rsync_ver[PATH_MAX]; +char rsync[PATH_MAX + 128]; +char rsync_ver[PATH_MAX * 2]; struct lr_parent_child_list *parents; FILE *debug_log; /* Command line options */ struct option long_opts[] = { - {"source", required_argument, 0, 's'}, - {"target", required_argument, 0, 't'}, - {"mdt", required_argument, 0, 'm'}, - {"user", required_argument, 0, 'u'}, - {"statuslog", required_argument, 0, 'l'}, - {"verbose", no_argument, 0, 'v'}, - {"xattr", required_argument, 0, 'x'}, - {"dry-run", no_argument, 0, 'z'}, - /* Undocumented options follow */ - {"cl-clear", required_argument, 0, 'c'}, - {"use-rsync", no_argument, 0, 'r'}, - {"rsync-threshold", required_argument, 0, 'y'}, - {"start-recno", required_argument, 0, 'n'}, - {"abort-on-err",no_argument, 0, 'a'}, - {"debug", required_argument, 0, 'd'}, - {"debuglog", required_argument, 0, 'D'}, - {0, 0, 0, 0} -}; + { .val = 'l', .name = "statuslog", .has_arg = required_argument }, + { .val = 'm', .name = "mdt", .has_arg = required_argument }, + { .val = 's', .name = "source", .has_arg = required_argument }, + { .val = 't', .name = "target", .has_arg = required_argument }, + { .val = 'u', .name = "user", .has_arg = required_argument }, + { .val = 'v', .name = "verbose", .has_arg = no_argument }, + { .val = 'x', .name = "xattr", .has_arg = required_argument }, + { .val = 'z', .name = "dry-run", .has_arg = no_argument }, + /* Undocumented options follow */ + { .val = 'a', .name = "abort-on-err", .has_arg = no_argument }, + { .val = 'c', .name = "cl-clear", .has_arg = required_argument }, + { .val = 'd', .name = "debug", .has_arg = required_argument }, + { .val = 'D', .name = "debuglog", .has_arg = required_argument }, + { .val = 'n', .name = "start-recno", .has_arg = required_argument }, + { .val = 'r', .name = "use-rsync", .has_arg = no_argument }, + { .val = 'y', .name = "rsync-threshold", + .has_arg = required_argument }, + { .name = NULL } }; /* Command line usage */ void lr_usage() @@ -239,16 +234,6 @@ void lr_usage() "\t--dry-run don't write anything\n"); } -#define DEBUG_ENTRY(info) \ - lr_debug(D_TRACE, "***** Start %lld %s (%d) %s %s %s *****\n", \ - (info)->recno, changelog_type2str((info)->type), \ - (info)->type, (info)->tfid, (info)->pfid, (info)->name); - -#define DEBUG_EXIT(info, rc) \ - lr_debug(D_TRACE, "##### End %lld %s (%d) %s %s %s rc=%d #####\n", \ - (info)->recno, changelog_type2str((info)->type), \ - (info)->type, (info)->tfid, (info)->pfid, (info)->name, rc); - /* Print debug information. This is controlled by the value of the global variable 'debug' */ void lr_debug(int level, const char *fmt, ...) @@ -281,9 +266,8 @@ void * lr_grow_buf(void *buf, int size) /* Use rsync to replicate file data */ int lr_rsync_data(struct lr_info *info) { - int rc; - struct stat st_src, st_dest; - char cmd[PATH_MAX]; + struct stat st_src, st_dest; + int rc; lr_debug(DTRACE, "Syncing data%s\n", info->tfid); @@ -305,18 +289,28 @@ int lr_rsync_data(struct lr_info *info) if (st_src.st_mtime != st_dest.st_mtime || st_src.st_size != st_dest.st_size) { - /* XXX spawning off an rsync for every data sync and - * waiting synchronously is bad for performance. - * librsync could possibly used here. But it does not - * seem to be of production grade. Multi-threaded - * replication is also to be considered. - */ - int status; - snprintf(cmd, PATH_MAX, "%s --inplace %s %s", rsync, info->src, - info->dest); - lr_debug(DTRACE, "\t%s %s\n", cmd, info->tfid); - status = system(cmd); - if (status == -1) { + /* XXX spawning off an rsync for every data sync and + * waiting synchronously is bad for performance. + * librsync could possibly used here. But it does not + * seem to be of production grade. Multi-threaded + * replication is also to be considered. + */ + char *args[] = { + rsync, + "--inplace", + "--", + info->src, + info->dest, + NULL, + }; + extern char **environ; + int status; + + lr_debug(DTRACE, "\t%s %s %s %s %s %s\n", args[0], args[1], + args[2], args[3], args[4], info->tfid); + + status = callvpe(rsync, args, environ); + if (status < 0) { rc = -errno; } else if (WIFEXITED(status)) { status = WEXITSTATUS(status); @@ -389,31 +383,39 @@ int lr_copy_data(struct lr_info *info) info->bufsize = bufsize; } - while (1) { - rsize = read(fd_src, info->buf, bufsize); - if (rsize == 0) { - break; - } else if (rsize < 0) { - rc = -errno; - goto out; - } - errno = 0; - if (write(fd_dest, info->buf, rsize) != rsize) { - if (errno != 0) - rc = -errno; - else - rc = -EINTR; - } - } - fsync(fd_dest); + while (1) { + char *buf; + int wsize; + + buf = info->buf; + rsize = read(fd_src, buf, bufsize); + if (rsize == 0) { + rc = 0; + break; + } + if (rsize < 0) { + rc = -errno; + break; + } + do { + wsize = write(fd_dest, buf, rsize); + if (wsize <= 0) { + rc = -errno; + break; + } + rsize -= wsize; + buf += wsize; + } while (rsize > 0); + } + fsync(fd_dest); out: - if (fd_src != -1) - close(fd_src); - if (fd_dest != -1) - close(fd_dest); + if (fd_src != -1) + close(fd_src); + if (fd_dest != -1) + close(fd_dest); - return rc; + return rc; } /* Copy data from source to destination */ @@ -426,7 +428,7 @@ int lr_sync_data(struct lr_info *info) } /* Copy all attributes from file src to file dest */ -int lr_copy_attr(char *src, char *dest) +int lr_copy_attr(const char *src, const char *dest) { struct stat st; struct utimbuf time; @@ -496,9 +498,10 @@ int lr_copy_xattr(struct lr_info *info) rc, errno); if (rc == -1) { if (errno != ENOTSUP) { - fprintf(stderr, "Error replicating " - " xattr for %s: %d\n", - info->dest, errno); + fprintf(stderr, + "cannot replicate xattrs from '%s' to '%s': %s\n", + info->src, info->dest, + strerror(errno)); errors++; } rc = 0; @@ -542,7 +545,6 @@ void lr_get_FID_PATH(char *mntpt, char *fidstr, char *buf, int bufsize) /* Open-by-FID path is /.lustre/fid/[SEQ:OID:VER] */ snprintf(buf, bufsize, "%s/%s/fid/%s", mntpt, dot_lustre_name, fidstr); - return; } /* Read the symlink information into 'info->link' */ @@ -563,16 +565,16 @@ int lr_get_symlink(struct lr_info *info) strlen(status->ls_source)) == 0) { /* Strip source fs path and replace with target fs path. */ link = info->linktmp + strlen(status->ls_source); - snprintf(info->src, PATH_MAX, "%s%s", + snprintf(info->src, sizeof(info->src), "%s%s", status->ls_targets[info->target_no], link); link = info->src; } else { link = info->linktmp; } - strncpy(info->link, link, PATH_MAX); - info->link[PATH_MAX] = '\0'; - - return rc; + rc = snprintf(info->link, sizeof(info->link), "%s", link); + if (rc >= sizeof(info->link)) + rc = -E2BIG; + return rc; } /* Create file/directory/device file/symlink. */ @@ -602,8 +604,13 @@ int lr_mkfile(struct lr_info *info) } else { rc = mknod(info->dest, S_IFREG | 0777, 0); } - if (rc) - return -errno; + + if (rc < 0) { + if (errno == EEXIST) + rc = 0; + else + return -errno; + } /* Sync data and attributes */ if (info->type == CL_CREATE || info->type == CL_MKDIR) { @@ -628,24 +635,28 @@ int lr_mkfile(struct lr_info *info) int lr_add_pc(const char *pfid, const char *tfid, const char *name) { - struct lr_parent_child_list *p; - - p = calloc(1, sizeof(*p)); - if (!p) - return -ENOMEM; - if (strlen(pfid) > sizeof(p->pc_log.pcl_pfid)-1) + struct lr_parent_child_list *p; + size_t len; + + p = calloc(1, sizeof(*p)); + if (p == NULL) + return -ENOMEM; + len = snprintf(p->pc_log.pcl_pfid, sizeof(p->pc_log.pcl_pfid), + "%s", pfid); + if (len >= sizeof(p->pc_log.pcl_pfid)) goto out_err; - strncpy(p->pc_log.pcl_pfid, pfid, sizeof(p->pc_log.pcl_pfid)); - if (strlen(tfid) > sizeof(p->pc_log.pcl_tfid)-1) + len = snprintf(p->pc_log.pcl_tfid, sizeof(p->pc_log.pcl_tfid), + "%s", tfid); + if (len >= sizeof(p->pc_log.pcl_tfid)) goto out_err; - strncpy(p->pc_log.pcl_tfid, tfid, sizeof(p->pc_log.pcl_tfid)); - if (strlen(name) > sizeof(p->pc_log.pcl_name)-1) + len = snprintf(p->pc_log.pcl_name, sizeof(p->pc_log.pcl_name), + "%s", name); + if (len >= sizeof(p->pc_log.pcl_name)) goto out_err; - strncpy(p->pc_log.pcl_name, name, sizeof(p->pc_log.pcl_name)); - p->pc_next = parents; - parents = p; - return 0; + p->pc_next = parents; + parents = p; + return 0; out_err: free(p); @@ -655,18 +666,22 @@ out_err: void lr_cascade_move(const char *fid, const char *dest, struct lr_info *info) { struct lr_parent_child_list *curr, *prev; - char *d; + char d[4 * PATH_MAX + 1]; int rc; - d = calloc(1, PATH_MAX + 1); prev = curr = parents; while (curr) { if (strcmp(curr->pc_log.pcl_pfid, fid) == 0) { - snprintf(d, PATH_MAX, "%s/%s", dest, - curr->pc_log.pcl_name); - snprintf(info->src, PATH_MAX, "%s/%s/%s", - status->ls_targets[info->target_no], - SPECIAL_DIR, curr->pc_log.pcl_tfid); + if (snprintf(d, sizeof(d), "%s/%s", dest, + curr->pc_log.pcl_name) >= sizeof(d)) { + fprintf(stderr, "Buffer truncated\n"); + return; + } + if (snprintf(info->src, sizeof(info->src), "%s/%s/%s", + status->ls_targets[info->target_no], + SPECIAL_DIR, curr->pc_log.pcl_tfid) >= + sizeof(info->src)) + return; rc = rename(info->src, d); if (rc == -1) { fprintf(stderr, "Error renaming file " @@ -674,11 +689,11 @@ void lr_cascade_move(const char *fid, const char *dest, struct lr_info *info) info->src, d, errno); errors++; } - lr_cascade_move(curr->pc_log.pcl_tfid, d, info); if (curr == parents) parents = curr->pc_next; else prev->pc_next = curr->pc_next; + lr_cascade_move(curr->pc_log.pcl_tfid, d, info); free(curr); prev = curr = parents; @@ -687,8 +702,6 @@ void lr_cascade_move(const char *fid, const char *dest, struct lr_info *info) curr = curr->pc_next; } } - - free(d); } /* remove [info->spfid, info->sfid] from parents */ @@ -715,7 +728,7 @@ int lr_mk_special(struct lr_info *info) { int rc; - snprintf(info->dest, PATH_MAX, "%s/%s/%s", + snprintf(info->dest, sizeof(info->dest), "%s/%s/%s", status->ls_targets[info->target_no], SPECIAL_DIR, info->tfid); @@ -744,14 +757,26 @@ int lr_rmfile(struct lr_info *info) /* Recursively remove directory and its contents */ int lr_rm_recursive(struct lr_info *info) { - int rc; - - snprintf(info->cmd, PATH_MAX, "rm -rf %s", info->dest); - rc = system(info->cmd); - if (rc == -1) - rc = -errno; + char *args[] = { + "rm", + "-rf", + "--", + info->dest, + NULL, + }; + extern char **environ; + int status; + int rc; + + status = callvpe("/bin/rm", args, environ); + if (status < 0) + rc = -errno; + else if (WIFEXITED(status)) + rc = WEXITSTATUS(status) == 0 ? 0 : -EINVAL; + else + rc = -EINTR; - return rc; + return rc; } /* Remove a file under SPECIAL_DIR with its tfid as its name. */ @@ -759,7 +784,7 @@ int lr_rm_special(struct lr_info *info) { int rc; - snprintf(info->dest, PATH_MAX, "%s/%s/%s", + snprintf(info->dest, sizeof(info->dest), "%s/%s/%s", status->ls_targets[info->target_no], SPECIAL_DIR, info->tfid); rc = lr_rmfile(info); @@ -803,11 +828,13 @@ int lr_create(struct lr_info *info) /* Is f2p(pfid)+name != f2p(tfid)? If not the file has moved. */ len = strlen(info->path); if (len == 1 && info->path[0] == '/') - snprintf(info->dest, PATH_MAX, "%s", info->name); + snprintf(info->dest, sizeof(info->dest), "%s", info->name); else if (len - 1 > 0 && info->path[len - 1] == '/') - snprintf(info->dest, PATH_MAX, "%s%s", info->path, info->name); + snprintf(info->dest, sizeof(info->dest), "%s%s", info->path, + info->name); else - snprintf(info->dest, PATH_MAX, "%s/%s", info->path, info->name); + snprintf(info->dest, sizeof(info->dest), "%s/%s", info->path, + info->name); lr_debug(DTRACE, "dest = %s; savedpath = %s\n", info->dest, info->savedpath); @@ -820,8 +847,8 @@ int lr_create(struct lr_info *info) /* Is f2p(pfid) present on the target? If not, the parent has moved */ if (!mkspecial) { - snprintf(info->dest, PATH_MAX, "%s/%s", status->ls_targets[0], - info->path); + snprintf(info->dest, sizeof(info->dest), "%s/%s", + status->ls_targets[0], info->path); if (access(info->dest, F_OK) != 0) { lr_debug(DTRACE, "create: parent %s not found\n", info->dest); @@ -830,10 +857,10 @@ int lr_create(struct lr_info *info) } for (info->target_no = 0; info->target_no < status->ls_num_targets; info->target_no++) { - snprintf(info->dest, PATH_MAX, "%s/%s", + snprintf(info->dest, sizeof(info->dest), "%s/%s", status->ls_targets[info->target_no], info->savedpath); lr_get_FID_PATH(status->ls_source, info->tfid, info->src, - PATH_MAX); + PATH_MAX); if (!mkspecial) rc1 = lr_mkfile(info); @@ -869,7 +896,7 @@ int lr_remove(struct lr_info *info) rc = rc1; continue; } - snprintf(info->dest, PATH_MAX, "%s/%s/%s", + snprintf(info->dest, sizeof(info->dest), "%s/%s/%s", status->ls_targets[info->target_no], info->path, info->name); @@ -897,7 +924,7 @@ int lr_move(struct lr_info *info) int special_dest = 0; char srcpath[PATH_MAX + 1] = ""; - LASSERT(info->is_extended); + assert(info->is_extended); rc_src = lr_get_path(info, info->spfid); if (rc_src < 0 && rc_src != -ENOENT) @@ -912,21 +939,22 @@ int lr_move(struct lr_info *info) info->target_no++) { if (!rc_dest) { - snprintf(info->dest, PATH_MAX, "%s/%s", + snprintf(info->dest, sizeof(info->dest), "%s/%s", status->ls_targets[info->target_no], info->path); if (access(info->dest, F_OK) != 0) { rc_dest = -errno; } else { - snprintf(info->dest, PATH_MAX, "%s/%s/%s", - status->ls_targets[info->target_no], - info->path, info->name); + snprintf(info->dest, sizeof(info->dest), + "%s/%s/%s", + status->ls_targets[info->target_no], + info->path, info->name); } lr_debug(DINFO, "dest path %s rc_dest=%d\n", info->dest, rc_dest); } if (rc_dest == -ENOENT) { - snprintf(info->dest, PATH_MAX, "%s/%s/%s", + snprintf(info->dest, sizeof(info->dest), "%s/%s/%s", status->ls_targets[info->target_no], SPECIAL_DIR, info->sfid); special_dest = 1; @@ -934,7 +962,7 @@ int lr_move(struct lr_info *info) } if (!rc_src) { - snprintf(info->src, PATH_MAX, "%s/%s/%s", + snprintf(info->src, sizeof(info->src), "%s/%s/%s", status->ls_targets[info->target_no], srcpath, info->sname); lr_debug(DINFO, "src path %s rc_src=%d\n", info->src, @@ -942,7 +970,7 @@ int lr_move(struct lr_info *info) } if (rc_src == -ENOENT || (access(info->src, F_OK) != 0 && errno == ENOENT)) { - snprintf(info->src, PATH_MAX, "%s/%s/%s", + snprintf(info->src, sizeof(info->src), "%s/%s/%s", status->ls_targets[info->target_no], SPECIAL_DIR, info->sfid); special_src = 1; @@ -958,12 +986,12 @@ int lr_move(struct lr_info *info) lr_debug(DINFO, "rename returns %d\n", rc1); } - if (special_src) { + if (special_src) rc1 = lr_remove_pc(info->spfid, info->sfid); - if (!special_dest) - lr_cascade_move(info->sfid, info->dest, info); - } - if (special_dest) + + if (!special_dest) + lr_cascade_move(info->sfid, info->dest, info); + else rc1 = lr_add_pc(info->pfid, info->sfid, info->name); lr_debug(DINFO, "move: %s [to] %s rc1=%d, errno=%d\n", @@ -978,7 +1006,6 @@ int lr_move(struct lr_info *info) int lr_link(struct lr_info *info) { int i; - int len; int rc; int rc1; struct stat st; @@ -991,54 +1018,75 @@ int lr_link(struct lr_info *info) for (info->target_no = 0; info->target_no < status->ls_num_targets; info->target_no++) { - info->src[0] = 0; - info->dest[0] = 0; - rc1 = 0; + info->src[0] = 0; + info->dest[0] = 0; + rc1 = 0; + + /* + * The changelog record has the new parent directory FID and + * name of the target file. So info->dest can be constructed + * by getting the path of the new parent directory and + * appending the target file name. + */ + rc1 = lr_get_path(info, info->pfid); + lr_debug(rc1 ? 0 : DTRACE, "\tparent fid2path %s, %s, rc=%d\n", + info->path, info->name, rc1); + + if (rc1 == 0) { + snprintf(info->dest, sizeof(info->dest), "%s/%s/%s", + status->ls_targets[info->target_no], + info->path, info->name); + lr_debug(DINFO, "link destination is %s\n", info->dest); + } + + /* Search through the hardlinks to get the src */ + for (i = 0; i < st.st_nlink && info->src[0] == 0; i++) { + size_t len; - /* Search through the hardlinks to get the src and dest */ - for (i = 0; i < st.st_nlink && (info->src[0] == 0 || - info->dest[0] == 0); i++) { rc1 = lr_get_path_ln(info, info->tfid, i); lr_debug(rc1 ? 0:DTRACE, "\tfid2path %s, %s, %d rc=%d\n", info->path, info->name, i, rc1); if (rc1) break; - len = strlen(info->path) - strlen(info->name); - if (len > 0 && strcmp(info->path + len, - info->name) == 0) - snprintf(info->dest, PATH_MAX, "%s/%s", - status->ls_targets[info->target_no], - info->path); - else if (info->src[0] == 0) - snprintf(info->src, PATH_MAX, "%s/%s", - status->ls_targets[info->target_no], - info->path); - } + /* + * Compare the path of target FID with info->dest + * to find out info->src. + */ + len = sizeof(status->ls_targets[info->target_no]) + + sizeof(info->path); + char srcpath[len + 1]; + + snprintf(srcpath, sizeof(srcpath), "%s/%s", + status->ls_targets[info->target_no], + info->path); + + if (strcmp(srcpath, info->dest) != 0) { + snprintf(info->src, sizeof(info->src), "%s", + srcpath); + lr_debug(DINFO, "link source is %s\n", + info->src); + } + } if (rc1) { rc = rc1; continue; } - if (info->src[0] == 0 || info->dest[0] == 0) - /* Could not find the source or destination. - This can happen when some links don't exist - anymore. */ - return -EINVAL; - if (info->src[0] == 0) - snprintf(info->src, PATH_MAX, "%s/%s/%s", + snprintf(info->src, sizeof(info->src), "%s/%s/%s", status->ls_targets[info->target_no], SPECIAL_DIR, info->tfid); else if (info->dest[0] == 0) - snprintf(info->dest, PATH_MAX, "%s/%s/%s", + snprintf(info->dest, sizeof(info->dest), "%s/%s/%s", status->ls_targets[info->target_no], SPECIAL_DIR, info->tfid); - rc1 = link(info->src, info->dest); - lr_debug(rc1?0:DINFO, "link: %s [to] %s; rc1=%d %s\n", - info->src, info->dest, rc1, strerror(errno)); + rc1 = link(info->src, info->dest); + lr_debug(DINFO, "link: %s [to] %s; rc1=%d %s\n", + info->src, info->dest, rc1, + strerror(rc1 ? errno : 0)); if (rc1) rc = rc1; @@ -1046,6 +1094,30 @@ int lr_link(struct lr_info *info) return rc; } +int lr_set_dest_for_attr(struct lr_info *info) +{ + int rc; + + snprintf(info->dest, sizeof(info->dest), "%s/%s", + status->ls_targets[info->target_no], info->path); + rc = access(info->dest, F_OK); + if (rc < 0) + rc = -errno; + + if (rc != -ENOENT) + return rc; + + snprintf(info->dest, sizeof(info->dest), "%s/%s/%s", + status->ls_targets[info->target_no], SPECIAL_DIR, + info->tfid); + + rc = access(info->dest, F_OK); + if (rc < 0) + return -errno; + + return 0; +} + /* Replicate file attributes */ int lr_setattr(struct lr_info *info) { @@ -1063,9 +1135,10 @@ int lr_setattr(struct lr_info *info) for (info->target_no = 0; info->target_no < status->ls_num_targets; info->target_no++) { + rc = lr_set_dest_for_attr(info); + if (rc < 0) + continue; - snprintf(info->dest, PATH_MAX, "%s/%s", - status->ls_targets[info->target_no], info->path); lr_debug(DINFO, "setattr: %s %s %s", info->src, info->dest, info->tfid); @@ -1094,9 +1167,10 @@ int lr_setxattr(struct lr_info *info) for (info->target_no = 0; info->target_no < status->ls_num_targets; info->target_no++) { + rc = lr_set_dest_for_attr(info); + if (rc < 0) + continue; - snprintf(info->dest, PATH_MAX, "%s/%s", - status->ls_targets[info->target_no], info->path); lr_debug(DINFO, "setxattr: %s %s %s\n", info->src, info->dest, info->tfid); @@ -1111,31 +1185,43 @@ int lr_setxattr(struct lr_info *info) /* Parse a line of changelog entry */ int lr_parse_line(void *priv, struct lr_info *info) { - struct changelog_ext_rec *rec; - - if (llapi_changelog_recv(priv, &rec) != 0) - return -1; - - info->is_extended = CHANGELOG_REC_EXTENDED(rec); - info->recno = rec->cr_index; - info->type = rec->cr_type; - sprintf(info->tfid, DFID, PFID(&rec->cr_tfid)); - sprintf(info->pfid, DFID, PFID(&rec->cr_pfid)); - strncpy(info->name, rec->cr_name, rec->cr_namelen); - - if (fid_is_sane(&rec->cr_sfid)) { - sprintf(info->sfid, DFID, PFID(&rec->cr_sfid)); - sprintf(info->spfid, DFID, PFID(&rec->cr_spfid)); - strncpy(info->sname, changelog_rec_sname(rec), - changelog_rec_snamelen(rec)); - info->sname[changelog_rec_snamelen(rec)] = '\0'; + struct changelog_rec *rec; + struct changelog_ext_rename *rnm; + size_t namelen; + size_t copylen = sizeof(info->name); + + if (llapi_changelog_recv(priv, &rec) != 0) + return -1; + + info->is_extended = !!(rec->cr_flags & CLF_RENAME); + info->recno = rec->cr_index; + info->type = rec->cr_type; + snprintf(info->tfid, sizeof(info->tfid), DFID, PFID(&rec->cr_tfid)); + snprintf(info->pfid, sizeof(info->pfid), DFID, PFID(&rec->cr_pfid)); + + namelen = strnlen(changelog_rec_name(rec), rec->cr_namelen); + if (copylen > namelen + 1) + copylen = namelen + 1; + snprintf(info->name, copylen, "%s", changelog_rec_name(rec)); + + /* Don't use rnm if CLF_RENAME isn't set */ + rnm = changelog_rec_rename(rec); + if (rec->cr_flags & CLF_RENAME && !fid_is_zero(&rnm->cr_sfid)) { + copylen = sizeof(info->sname); + + snprintf(info->sfid, sizeof(info->sfid), DFID, + PFID(&rnm->cr_sfid)); + snprintf(info->spfid, sizeof(info->spfid), DFID, + PFID(&rnm->cr_spfid)); + namelen = changelog_rec_snamelen(rec); + if (copylen > namelen + 1) + copylen = namelen + 1; + snprintf(info->sname, copylen, "%s", changelog_rec_sname(rec)); if (verbose > 1) printf("Rec %lld: %d %s %s\n", info->recno, info->type, info->name, info->sname); } else { - info->name[rec->cr_namelen] = '\0'; - if (verbose > 1) printf("Rec %lld: %d %s\n", info->recno, info->type, info->name); @@ -1170,11 +1256,9 @@ void lr_backup_log() if (logbackedup) return; - snprintf(backupfile, PATH_MAX, "%s.old", statuslog); + snprintf(backupfile, sizeof(backupfile), "%s.old", statuslog); (void) rename(statuslog, backupfile); logbackedup = 1; - - return; } /* Save replication parameters to a statuslog. */ @@ -1236,31 +1320,50 @@ int lr_read_log() return 0; s = calloc(1, read_size); - if (s == NULL) - GOTO(out, rc = -ENOMEM); - - fd = open(statuslog, O_RDONLY); - if (fd == -1) - GOTO(out, rc = -errno); - size = read(fd, s, read_size); - if (size != read_size) - GOTO(out, rc = -EINVAL); - if (read_size < s->ls_size) { - read_size = s->ls_size; - s = lr_grow_buf(s, read_size); - if (s == NULL) - GOTO(out, rc = -ENOMEM); - if (lseek(fd, 0, SEEK_SET) == -1) - GOTO(out, rc = -errno); - size = read(fd, s, read_size); - if (size != read_size) - GOTO(out, rc = -EINVAL); - } + if (s == NULL) { + rc = -ENOMEM; + goto out; + } + + fd = open(statuslog, O_RDONLY); + if (fd == -1) { + rc = -errno; + goto out; + } + + size = read(fd, s, read_size); + if (size != read_size) { + rc = -EINVAL; + goto out; + } + + if (read_size < s->ls_size) { + read_size = s->ls_size; + s = lr_grow_buf(s, read_size); + if (s == NULL) { + rc = -ENOMEM; + goto out; + } + + if (lseek(fd, 0, SEEK_SET) == -1) { + rc = -ENOMEM; + goto out; + } + + size = read(fd, s, read_size); + if (size != read_size) { + rc = -EINVAL; + goto out; + } + } + + while (read(fd, &rec, sizeof(rec)) != 0) { + tmp = calloc(1, sizeof(*tmp)); + if (!tmp) { + rc = -ENOMEM; + goto out; + } - while (read(fd, &rec, sizeof(rec)) != 0) { - tmp = calloc(1, sizeof(*tmp)); - if (!tmp) - GOTO(out, rc = -ENOMEM); tmp->pc_log = rec; tmp->pc_next = parents; parents = tmp; @@ -1270,8 +1373,11 @@ int lr_read_log() if (status->ls_num_targets == 0) { if (status->ls_size != s->ls_size) { status = lr_grow_buf(status, s->ls_size); - if (status == NULL) - GOTO(out, rc = -ENOMEM); + if (status == NULL) { + rc = -ENOMEM; + goto out; + } + status->ls_size = s->ls_size; } status->ls_num_targets = s->ls_num_targets; @@ -1281,20 +1387,25 @@ int lr_read_log() if (status->ls_last_recno == -1) status->ls_last_recno = s->ls_last_recno; - if (status->ls_registration[0] == '\0') - strncpy(status->ls_registration, s->ls_registration, - LR_NAME_MAXLEN); + if (status->ls_registration[0] == '\0') + snprintf(status->ls_registration, + sizeof(status->ls_registration), "%s", + s->ls_registration); - if (status->ls_mdt_device[0] == '\0') - strncpy(status->ls_mdt_device, s->ls_mdt_device, - LR_NAME_MAXLEN); + if (status->ls_mdt_device[0] == '\0') + snprintf(status->ls_mdt_device, + sizeof(status->ls_mdt_device), "%s", + s->ls_mdt_device); - if (status->ls_source_fs[0] == '\0') - strncpy(status->ls_source_fs, s->ls_source_fs, - LR_NAME_MAXLEN); + if (status->ls_source_fs[0] == '\0') + snprintf(status->ls_source_fs, + sizeof(status->ls_source_fs), "%s", + s->ls_source_fs); - if (status->ls_source[0] == '\0') - strncpy(status->ls_source, s->ls_source, PATH_MAX); + if (status->ls_source[0] == '\0') + snprintf(status->ls_source, + sizeof(status->ls_source), "%s", + s->ls_source); out: if (fd != -1) @@ -1308,38 +1419,34 @@ int lr_read_log() processing. */ int lr_clear_cl(struct lr_info *info, int force) { - char mdt_device[LR_NAME_MAXLEN + 1]; - long long rec; - int rc = 0; + char mdt_device[LR_NAME_MAXLEN + 1]; + int rc = 0; if (force || info->recno > status->ls_last_recno + CLEAR_INTERVAL) { - if (info->type == CL_RENAME) - rec = info->recno + 1; - else - rec = info->recno; if (!noclear && !dryrun) { /* llapi_changelog_clear modifies the mdt * device name so make a copy of it until this * is fixed. - */ - strncpy(mdt_device, status->ls_mdt_device, - LR_NAME_MAXLEN); + */ + snprintf(mdt_device, sizeof(mdt_device), "%s", + status->ls_mdt_device); rc = llapi_changelog_clear(mdt_device, status->ls_registration, - rec); + info->recno); if (rc) - printf("Changelog clear (%s, %s, %lld) " - "returned %d\n", status->ls_mdt_device, - status->ls_registration, rec, rc); - } - if (!rc && !dryrun) { - status->ls_last_recno = rec; - lr_write_log(); + printf("Changelog clear (%s, %s, %lld) " + "returned %d\n", status->ls_mdt_device, + status->ls_registration, info->recno, + rc); + } - } - } + if (!rc && !dryrun) { + status->ls_last_recno = info->recno; + lr_write_log(); + } + } - return rc; + return rc; } /* Locate a usable version of rsync. At this point we'll use any @@ -1350,12 +1457,12 @@ int lr_locate_rsync() int len; /* Locate rsync */ - snprintf(rsync, PATH_MAX, "%s -p %s", TYPE, RSYNC); + snprintf(rsync, sizeof(rsync), "%s -p %s", TYPE, RSYNC); fp = popen(rsync, "r"); if (fp == NULL) return -1; - if (fgets(rsync, PATH_MAX, fp) == NULL) { + if (fgets(rsync, sizeof(rsync), fp) == NULL) { fclose(fp); return -1; } @@ -1366,12 +1473,12 @@ int lr_locate_rsync() fclose(fp); /* Determine the version of rsync */ - snprintf(rsync_ver, PATH_MAX, "%s --version", rsync); + snprintf(rsync_ver, sizeof(rsync_ver), "%s --version", rsync); fp = popen(rsync_ver, "r"); if (fp == NULL) return -1; - if (fgets(rsync_ver, PATH_MAX, fp) == NULL) { + if (fgets(rsync_ver, sizeof(rsync_ver), fp) == NULL) { fclose(fp); return -1; } @@ -1400,7 +1507,8 @@ void lr_print_status(struct lr_info *info) if (statuslog != NULL) printf("Statuslog: %s\n", statuslog); printf("Changelog registration: %s\n", status->ls_registration); - printf("Starting changelog record: "LPD64"\n", status->ls_last_recno); + printf("Starting changelog record: %jd\n", + (uintmax_t)status->ls_last_recno); if (noxattr) printf("Replicate xattrs: no\n"); if (noclear) @@ -1440,9 +1548,18 @@ int lr_replicate() "mountpoint.\n"); goto out; } - if (status->ls_mdt_device[0] == '\0') - snprintf(status->ls_mdt_device, LR_NAME_MAXLEN, "%s%s", - status->ls_source_fs, DEFAULT_MDT); + + if (status->ls_mdt_device[0] == '\0') { + int len; + + len = snprintf(status->ls_mdt_device, + sizeof(status->ls_mdt_device), "%s%s", + status->ls_source_fs, DEFAULT_MDT); + if (len >= sizeof(status->ls_mdt_device)) { + rc = -E2BIG; + goto out; + } + } ext = calloc(1, sizeof(struct lr_info)); if (ext == NULL) { @@ -1451,8 +1568,8 @@ int lr_replicate() } for (i = 0, xattr_not_supp = 0; i < status->ls_num_targets; i++) { - snprintf(info->dest, PATH_MAX, "%s/%s", status->ls_targets[i], - SPECIAL_DIR); + snprintf(info->dest, sizeof(info->dest), "%s/%s", + status->ls_targets[i], SPECIAL_DIR); rc = mkdir(info->dest, 0777); if (rc == -1 && errno != EEXIST) { fprintf(stderr, "Error writing to target path %s.\n", @@ -1473,15 +1590,29 @@ int lr_replicate() lr_print_status(info); - /* Open changelogs for consumption*/ - rc = llapi_changelog_start(&changelog_priv, CHANGELOG_FLAG_BLOCK, - status->ls_source_fs, status->ls_last_recno); + /* Open changelogs for consumption*/ + rc = llapi_changelog_start(&changelog_priv, + CHANGELOG_FLAG_BLOCK | + CHANGELOG_FLAG_JOBID | + CHANGELOG_FLAG_EXTRA_FLAGS, + status->ls_mdt_device, status->ls_last_recno); if (rc < 0) { fprintf(stderr, "Error opening changelog file for fs %s.\n", status->ls_source_fs); goto out; } + rc = llapi_changelog_set_xflags(changelog_priv, + CHANGELOG_EXTRA_FLAG_UIDGID | + CHANGELOG_EXTRA_FLAG_NID | + CHANGELOG_EXTRA_FLAG_OMODE | + CHANGELOG_EXTRA_FLAG_XATTR); + if (rc < 0) { + fprintf(stderr, "Error setting xflag in changelog for fs %s.\n", + status->ls_source_fs); + goto out; + } + while (!quit && lr_parse_line(changelog_priv, info) == 0) { rc = 0; if (info->type == CL_RENAME && !info->is_extended) { @@ -1495,15 +1626,20 @@ int lr_replicate() memcpy(info->spfid, info->pfid, sizeof(info->spfid)); memcpy(info->tfid, ext->tfid, sizeof(info->tfid)); memcpy(info->pfid, ext->pfid, sizeof(info->pfid)); - strncpy(info->sname, info->name, sizeof(info->sname)); - strncpy(info->name, ext->name, sizeof(info->name)); + snprintf(info->sname, sizeof(info->sname), "%s", + info->name); + snprintf(info->name, sizeof(info->name), "%s", + ext->name); info->is_extended = 1; + info->recno = ext->recno; /* For lr_clear_cl(). */ } if (dryrun) continue; - DEBUG_ENTRY(info); + lr_debug(DTRACE, "***** Start %lld %s (%d) %s %s %s *****\n", + info->recno, changelog_type2str(info->type), + info->type, info->tfid, info->pfid, info->name); switch(info->type) { case CL_CREATE: @@ -1526,12 +1662,14 @@ int lr_replicate() case CL_SETATTR: rc = lr_setattr(info); break; - case CL_XATTR: + case CL_SETXATTR: rc = lr_setxattr(info); break; case CL_CLOSE: case CL_EXT: case CL_OPEN: + case CL_GETXATTR: + case CL_DN_OPEN: case CL_LAYOUT: case CL_MARK: /* Nothing needs to be done for these entries */ @@ -1539,7 +1677,11 @@ int lr_replicate() default: break; } - DEBUG_EXIT(info, rc); + + lr_debug(DTRACE, "##### End %lld %s (%d) %s %s %s rc=%d #####\n", + info->recno, changelog_type2str(info->type), + info->type, info->tfid, info->pfid, info->name, rc); + if (rc && rc != -ENOENT) { lr_print_failure(info, rc); errors++; @@ -1547,10 +1689,6 @@ int lr_replicate() break; } lr_clear_cl(info, 0); - if (debug) { - bzero(info, sizeof(struct lr_info)); - bzero(ext, sizeof(struct lr_info)); - } } llapi_changelog_fini(&changelog_priv); @@ -1603,7 +1741,8 @@ int main(int argc, char *argv[]) break; case 's': /* Assume absolute paths */ - strncpy(status->ls_source, optarg, PATH_MAX); + snprintf(status->ls_source, sizeof(status->ls_source), + "%s", optarg); break; case 't': status->ls_num_targets++; @@ -1624,16 +1763,18 @@ int main(int argc, char *argv[]) if (status == NULL) return -ENOMEM; } - strncpy(status->ls_targets[status->ls_num_targets - 1], - optarg, - PATH_MAX); - break; - case 'm': - strncpy(status->ls_mdt_device, optarg, LR_NAME_MAXLEN); - break; - case 'u': - strncpy(status->ls_registration, optarg, - LR_NAME_MAXLEN); + snprintf(status->ls_targets[status->ls_num_targets - 1], + sizeof(status->ls_targets[0]), "%s", optarg); + break; + case 'm': + snprintf(status->ls_mdt_device, + sizeof(status->ls_mdt_device), + "%s", optarg); + break; + case 'u': + snprintf(status->ls_registration, + sizeof(status->ls_registration), + "%s", optarg); break; case 'l': statuslog = optarg; @@ -1723,13 +1864,6 @@ int main(int argc, char *argv[]) return -1; } - /* This plumbing is needed for some of the ioctls behind - llapi calls to work. */ - if (obd_initialize(argc, argv) < 0) { - fprintf(stderr, "obd_initialize failed.\n"); - exit(-1); - } - rc = lr_locate_rsync(); if (use_rsync && rc != 0) { fprintf(stderr, "Error: unable to locate %s.\n", RSYNC);