Whamcloud - gitweb
LU-10986 lfs: make lfs project tolerant errors 02/34102/5
authorWang Shilong <wshilong@ddn.com>
Wed, 2 May 2018 08:54:15 +0000 (16:54 +0800)
committerOleg Drokin <green@whamcloud.com>
Sat, 2 Mar 2019 01:30:13 +0000 (01:30 +0000)
This patch try to fix following problems:
1)command hang on pipe file, reproduced by following steps:
 $ mkfifo tmp/pipe
 $ lfs project -srp 500 tmp -->this will never finish.

Problem is opening a pipe file will be blocked in default
without O_NOBLOCK or O_NODELAY flag.

2)If a symbolic link with missing target exists, command
returns error and does not process remaining entries.

we should fix this problem by allowing command process
further even it hit some errors.

3)fix a wrong check for MAX_PATH

Lustre-change: https://review.whamcloud.com/32243
Lustre-commit: d189024bd3065c69c51ba90f6228c3ea28419dd0

Signed-off-by: Wang Shilong <wshilong@ddn.com>
Change-Id: I7d08a7547e6b1351a1eff23063da6cd9c4cdc5e3
Reviewed-on: https://review.whamcloud.com/34102
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Tested-by: Jenkins
Tested-by: Maloo <maloo@whamcloud.com>
lustre/tests/sanity-quota.sh
lustre/utils/lfs_project.c

index a4466bb..d628a91 100755 (executable)
@@ -2983,7 +2983,7 @@ test_54() {
 }
 run_test 54 "basic lfs project interface test"
 
-test_56 () {
+test_56() {
        setup_quota_test || error "setup quota failed with $?"
 
        set_ost_qtype $QTYPE || error "enable ost quota failed"
@@ -3002,6 +3002,27 @@ test_56 () {
 }
 run_test 56 "lfs quota -t should work well"
 
+test_57() {
+       setup_quota_test || error "setup quota failed with $?"
+
+       local dir="$DIR/$tdir/dir"
+       mkdir -p $dir
+       mkfifo $dir/pipe
+       #try to change pipe file should not hang and return failure
+       wait_update_facet client "$LFS project -sp 1 $dir/pipe 2>&1 |
+               awk -F ':' '{ print \\\$2 }'" \
+                       " failed to get xattr for '$dir/pipe'" || return 1
+       #command can process further if it hit some errors
+       touch $dir/aaa $dir/bbb
+       #create one invalid link file
+       ln -s $dir/not_exist_file $dir/ccc
+       local cnt=$(lfs project -r $dir 2>/dev/null | wc -l)
+       [ $cnt -eq 2 ] || error "expected 2 got $cnt"
+
+       cleanup_quota_test
+}
+run_test 57 "lfs project could tolerate errors"
+
 quota_fini()
 {
        do_nodes $(comma_list $(nodes_list)) "lctl set_param debug=-quota"
index 180447a..07eff3c 100644 (file)
@@ -79,7 +79,7 @@ static int project_get_xattr(const char *pathname, struct fsxattr *fsx)
 {
        int ret, fd;
 
-       fd = open(pathname, O_RDONLY | O_NOCTTY);
+       fd = open(pathname, O_RDONLY | O_NOCTTY | O_NDELAY);
        if (fd < 0) {
                fprintf(stderr, "%s: failed to open '%s': %s\n",
                        progname, pathname, strerror(errno));
@@ -224,6 +224,7 @@ lfs_project_handle_dir(struct list_head *head, const char *pathname,
        struct dirent *ent;
        DIR *dir;
        int ret = 0;
+       int rc;
 
        dir = opendir(pathname);
        if (dir == NULL) {
@@ -233,24 +234,31 @@ lfs_project_handle_dir(struct list_head *head, const char *pathname,
                return ret;
        }
 
-       while (ret == 0 && (ent = readdir(dir)) != NULL) {
+       while ((ent = readdir(dir)) != NULL) {
                /* skip "." and ".." */
                if (strcmp(ent->d_name, ".") == 0 ||
                    strcmp(ent->d_name, "..") == 0)
                        continue;
 
-               if (strlen(ent->d_name) + strlen(pathname) >=
-                   sizeof(fullname) + 1) {
+               if (strlen(ent->d_name) + strlen(pathname) + 1 >=
+                   sizeof(fullname)) {
                        ret = -ENAMETOOLONG;
                        errno = ENAMETOOLONG;
-                       break;
+                       fprintf(stderr, "%s: ignored too long path: %s/%s\n",
+                                       progname, pathname, ent->d_name);
+                       continue;
                }
                snprintf(fullname, PATH_MAX, "%s/%s", pathname,
                         ent->d_name);
 
-               ret = func(fullname, phc);
-               if (phc->recursive && ret == 0 && ent->d_type == DT_DIR)
-                       ret = lfs_project_item_alloc(head, fullname);
+               rc = func(fullname, phc);
+               if (rc && !ret)
+                       ret = rc;
+               if (phc->recursive && ent->d_type == DT_DIR) {
+                       rc = lfs_project_item_alloc(head, fullname);
+                       if (rc && !ret)
+                               ret = rc;
+               }
        }
 
        if (ret)
@@ -270,7 +278,7 @@ static int lfs_project_iterate(const char *pathname,
        struct list_head head;
        struct stat st;
        int ret = 0;
-       bool top_dir = true;
+       int rc = 0;
 
        ret = stat(pathname, &st);
        if (ret) {
@@ -296,16 +304,13 @@ static int lfs_project_iterate(const char *pathname,
        while (!list_empty(&head)) {
                lpi = list_entry(head.next, struct lfs_project_item, lpi_list);
                list_del(&lpi->lpi_list);
-               if (ret == 0) {
-                       ret = lfs_project_handle_dir(&head, lpi->lpi_pathname,
+               if (rc == 0) {
+                       rc = lfs_project_handle_dir(&head, lpi->lpi_pathname,
                                                     phc, func);
-                       /* only ignore ENOENT error if this is
-                        * not top directory. */
-                       if (ret == -ENOENT && !top_dir)
-                               ret = 0;
+                       if (!ret && rc)
+                               ret = rc;
                }
                free(lpi);
-               top_dir = false;
        }
 
        return ret;