Whamcloud - gitweb
LU-12373 pcc: uncache the pcc copies when remove a PCC backend
[fs/lustre-release.git] / lustre / utils / libhsm_scanner.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; if not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2019, DDN Storage Corporation.
24  */
25 /*
26  * lustre/utils/libhsm_scanner.c
27  *
28  * Library for scanning HSM backend fs.
29  *
30  * Author: Qian Yingjin <qian@ddn.com>
31  */
32
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <dirent.h>
38 #include <sys/stat.h>
39 #include <sys/types.h>
40 #include <libcfs/util/list.h>
41 #include "libhsm_scanner.h"
42
43 struct hsm_scan_item {
44         struct list_head        hsi_item;
45         int                     hsi_depth;
46         char                    hsi_pathname[PATH_MAX];
47 };
48
49 static int hsm_scan_item_alloc(struct list_head *head,
50                                const char *pathname, int depth)
51 {
52         struct hsm_scan_item *item;
53         int rc;
54
55         if (strlen(pathname) >= PATH_MAX) {
56                 rc = -ENAMETOOLONG;
57                 llapi_error(LLAPI_MSG_ERROR, rc,
58                             "pathname is too long: %s\n", pathname);
59                 return rc;
60         }
61
62         item = malloc(sizeof(struct hsm_scan_item));
63         if (item == NULL) {
64                 rc = -ENOMEM;
65                 llapi_error(LLAPI_MSG_ERROR, rc,
66                             "cannot allocate hsm item for '%s'", pathname);
67                 return rc;
68         }
69
70         item->hsi_depth = depth;
71         strncpy(item->hsi_pathname, pathname, sizeof(item->hsi_pathname) - 1);
72         list_add_tail(&item->hsi_item, head);
73
74         return 0;
75 }
76
77 int hsm_scan_handle_dir(struct hsm_scan_control *hsc, struct list_head *head,
78                         struct hsm_scan_item *item)
79 {
80         char fullname[PATH_MAX + NAME_MAX + 1];
81         const char *pathname = item->hsi_pathname;
82         int depth = item->hsi_depth;
83         struct dirent *ent;
84         DIR *dir;
85         int ret;
86         int rc = 0;
87
88         dir = opendir(pathname);
89         if (dir == NULL) {
90                 rc = -errno;
91                 llapi_error(LLAPI_MSG_ERROR, rc, "failed to opendir '%s'",
92                             pathname);
93                 return rc;
94         }
95
96         while ((ent = readdir(dir)) != NULL) {
97                 /* skip "." and ".." */
98                 if (strcmp(ent->d_name, ".") == 0 ||
99                     strcmp(ent->d_name, "..") == 0)
100                         continue;
101
102                 llapi_printf(LLAPI_MSG_DEBUG,
103                              "check file %d:'%s' under directory '%s'\n",
104                              depth, ent->d_name, pathname);
105                 if (depth == 0 && ent->d_type == DT_DIR &&
106                     strcmp(ent->d_name, "shadow") == 0) {
107                         llapi_printf(LLAPI_MSG_DEBUG,
108                                      "skipping check of 'shadow' directory.\n");
109                 } else {
110                         if (ent->d_type == DT_REG) {
111                                 ret = hsc->hsc_func(pathname, ent->d_name, hsc);
112                                 if (ret && !rc) {
113                                         hsc->hsc_errnum++;
114                                         rc = ret;
115                                         /* ignore error, continue to check */
116                                 }
117                         } else if (ent->d_type == DT_DIR) {
118                                 if (strlen(ent->d_name) + strlen(pathname) + 1
119                                     >= sizeof(fullname)) {
120                                         rc = -ENAMETOOLONG;
121                                         errno = ENAMETOOLONG;
122                                         llapi_err_noerrno(LLAPI_MSG_ERROR,
123                                                           "ignore too long path: %s/%s\n",
124                                                           pathname,
125                                                           ent->d_name);
126                                         hsc->hsc_errnum++;
127                                         continue;
128                                 }
129                                 snprintf(fullname, sizeof(fullname), "%s/%s",
130                                          pathname, ent->d_name);
131                                 rc = hsm_scan_item_alloc(head, fullname,
132                                                          depth + 1);
133                         }
134                 }
135         }
136
137         if (rc)
138                 llapi_error(LLAPI_MSG_ERROR, rc, "failed to handle dir '%s'",
139                             pathname);
140
141         closedir(dir);
142         return rc;
143 }
144
145 int hsm_scan_process(struct hsm_scan_control *hsc)
146 {
147         struct hsm_scan_item *item;
148         struct list_head head;
149         struct stat st;
150         int ret = 0;
151         int rc;
152
153         if (hsc->hsc_type != HSMTOOL_POSIX_V1 &&
154             hsc->hsc_type != HSMTOOL_POSIX_V2)
155                 return -EOPNOTSUPP;
156
157         rc = stat(hsc->hsc_hsmpath, &st);
158         if (rc) {
159                 llapi_error(LLAPI_MSG_ERROR, rc, "failed to stat '%s'",
160                             hsc->hsc_hsmpath);
161                 return rc;
162         }
163
164         if (!S_ISDIR(st.st_mode)) {
165                 llapi_err_noerrno(LLAPI_MSG_ERROR,
166                                   "HSM root path '%s' must be a directory.",
167                                   hsc->hsc_hsmpath);
168                 return -EINVAL;
169         }
170
171         INIT_LIST_HEAD(&head);
172         rc = hsm_scan_item_alloc(&head, hsc->hsc_hsmpath, 0);
173         if (rc)
174                 return rc;
175
176         while (!list_empty(&head)) {
177                 item = list_entry(head.next, struct hsm_scan_item, hsi_item);
178                 list_del(&item->hsi_item);
179                 ret = hsm_scan_handle_dir(hsc, &head, item);
180                 if (!rc && ret)
181                         rc = ret;
182                 free(item);
183         }
184
185         return rc;
186 }