Whamcloud - gitweb
LU-8015 utils: fix lr_link() to get correct src and dest 99/19599/5
authorJian Yu <jian.yu@intel.com>
Fri, 15 Apr 2016 07:54:20 +0000 (00:54 -0700)
committerOleg Drokin <oleg.drokin@intel.com>
Fri, 22 Apr 2016 15:48:37 +0000 (15:48 +0000)
The current codes in lr_link() of lustre_rsync.c can not
find out the correct info->src and info->dest in the
following situations:
1) the source name ends with the destination name
2) the file has two links with the same name but
   in different directories

This patch fixes the above issue by using the path of the
parent FID and target name to construct info->dest, and
comparing the path of the target FID with info->dest to
get the correct info->src.

Test-Parameters: testlist=lustre-rsync-test
Signed-off-by: Jian Yu <jian.yu@intel.com>
Change-Id: Ia92b01c069bde01bd0f094017bd2502292afc7f8
Reviewed-on: http://review.whamcloud.com/19599
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: John L. Hammond <john.hammond@intel.com>
Reviewed-by: Jinshan Xiong <jinshan.xiong@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
lustre/tests/lustre-rsync-test.sh
lustre/utils/lustre_rsync.c

index b091763..d27e93d 100644 (file)
@@ -534,17 +534,18 @@ run_test 5b "Kill / restart lustre_rsync"
 
 # Test 6 - lustre_rsync large no of hard links
 test_6() {
-    init_src
-    init_changelog
+       init_src
+       init_changelog
 
-    local NUMLINKS=128
-    touch $DIR/$tdir/link0
-    local i=1
-    while [ $i -lt $NUMLINKS ];
-    do
-      ln $DIR/$tdir/link0  $DIR/$tdir/link${i}
-      i=$(expr $i + 1)
-    done
+       local num_links=128
+       local i
+
+       touch $DIR/$tdir/link0
+       for ((i = 1; i < num_links - 1; i++)); do
+               ln $DIR/$tdir/link0 $DIR/$tdir/link$i
+       done
+       # create an extra hard link of src name ending with dest name
+       ln $DIR/$tdir/link0 $DIR/$tdir/ink0
 
        local LRSYNC_LOG=$(generate_logname "lrsync_log")
        # Replicate the changes to $TGT
@@ -553,15 +554,16 @@ test_6() {
        check_diff $DIR/$tdir $TGT/$tdir
        check_diff $DIR/$tdir $TGT2/$tdir
 
-    local count1=$(ls -l $TGT/$tdir/link0 | sed -r 's/ +/ /g' | cut -f 2 -d ' ')
-    local count2=$(ls -l $TGT/$tdir/link0 | sed -r 's/ +/ /g' | cut -f 2 -d ' ')
-    if [[ $count1 -ne $NUMLINKS ]] ||  [[ $count2 -ne $NUMLINKS ]]; then
-       ls -l $TGT/$tdir/link0 $TGT2/$tdir/link0
-       error "Incorrect no of hard links found $count1, $count2"
-    fi
-    fini_changelog
-    cleanup_src_tgt
-    return 0
+       local count1=$(stat --format=%h $TGT/$tdir/link0)
+       local count2=$(stat --format=%h $TGT2/$tdir/link0)
+       if ((count1 != num_links || count2 != num_links)); then
+               ls -l $TGT/$tdir/link0 $TGT2/$tdir/link0
+               error "Incorrect no of hard links found $count1, $count2"
+       fi
+
+       fini_changelog
+       cleanup_src_tgt
+       return 0
 }
 run_test 6 "lustre_rsync large no of hard links"
 
index 3e196d5..c3eab0f 100644 (file)
@@ -989,7 +989,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;
@@ -1002,42 +1001,57 @@ 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 and dest */
-                for (i = 0; i < st.st_nlink && (info->src[0] == 0 ||
-                                                info->dest[0] == 0); i++) {
+               /* Search through the hardlinks to get the src */
+               for (i = 0; i < st.st_nlink && info->src[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.
+                        */
+                       char srcpath[PATH_MAX];
+
+                       snprintf(srcpath, sizeof(srcpath), "%s/%s",
+                                status->ls_targets[info->target_no],
+                                info->path);
+
+                       if (strcmp(srcpath, info->dest) != 0) {
+                               strlcpy(info->src, srcpath, sizeof(info->src));
+                               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",
                                 status->ls_targets[info->target_no],
@@ -1047,9 +1061,10 @@ int lr_link(struct lr_info *info)
                                 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;