Whamcloud - gitweb
LU-17676 build: configure should prefer to ask if
[fs/lustre-release.git] / lustre / utils / liblustreapi_pcc.c
1 /*
2  * LGPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the GNU Lesser General Public License
8  * (LGPL) version 2.1 or (at your discretion) any later version.
9  * (LGPL) version 2.1 accompanies this distribution, and is available at
10  * http://www.gnu.org/licenses/lgpl-2.1.html
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * LGPL HEADER END
18  */
19 /*
20  * Copyright (c) 2017, DDN Storage Corporation.
21  */
22 /*
23  * This file is part of Lustre, http://www.lustre.org/
24  */
25 /*
26  *
27  * lustreapi library for Persistent Client Cache.
28  *
29  * Author: Li Xi <lixi@ddn.com>
30  * Author: Qian Yingjin <qian@ddn.com>
31  */
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <lustre/lustreapi.h>
36 #include <linux/lustre/lustre_user.h>
37 #include <linux/lustre/lustre_fid.h>
38 #include <errno.h>
39 #include <unistd.h>
40 #include <stdlib.h>
41 #include <sys/ioctl.h>
42 #include "lustreapi_internal.h"
43
44 /**
45  * Fetch and attach a file to readwrite PCC.
46  *
47  */
48 static int llapi_pcc_attach_rw_fd(int fd, __u32 archive_id)
49 {
50         int rc;
51         struct ll_ioc_lease *data;
52
53         rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
54         if (rc < 0) {
55                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get lease");
56                 return rc;
57         }
58
59         data = malloc(offsetof(typeof(*data), lil_ids[1]));
60         if (!data) {
61                 rc = -ENOMEM;
62                 llapi_err_noerrno(LLAPI_MSG_ERROR,
63                                   "failed to allocate memory");
64                 return rc;
65         }
66
67         data->lil_mode = LL_LEASE_UNLCK;
68         data->lil_flags = LL_LEASE_PCC_ATTACH;
69         data->lil_count = 1;
70         data->lil_ids[0] = archive_id;
71         rc = llapi_lease_set(fd, data);
72         if (rc <= 0) {
73                 if (rc == 0) /* lost lease lock */
74                         rc = -EBUSY;
75                 llapi_error(LLAPI_MSG_ERROR, rc,
76                             "cannot attach with ID: %u", archive_id);
77         } else {
78                 rc = 0;
79         }
80
81         free(data);
82         return rc;
83 }
84
85 static int llapi_pcc_attach_rw(const char *path, __u32 archive_id)
86 {
87         int fd;
88         int rc;
89
90         fd = open(path, O_RDWR | O_NONBLOCK);
91         if (fd < 0) {
92                 rc = -errno;
93                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'",
94                             path);
95                 return rc;
96         }
97
98         rc = llapi_pcc_attach_rw_fd(fd, archive_id);
99
100         close(fd);
101         return rc;
102 }
103
104 static int llapi_pcc_attach_ro_fd(int fd, __u32 roid)
105 {
106         struct lu_pcc_attach attach;
107         int rc;
108
109         attach.pcca_id = roid;
110         attach.pcca_type = LU_PCC_READONLY;
111         rc = ioctl(fd, LL_IOC_PCC_ATTACH, &attach);
112         if (rc) {
113                 rc = -errno;
114                 llapi_error(LLAPI_MSG_ERROR, rc,
115                             "cannot attach the file to PCC with ID %u failed",
116                             roid);
117         }
118
119         return rc;
120 }
121
122 static int llapi_pcc_attach_ro(const char *path, __u32 roid)
123 {
124         int fd;
125         int rc;
126
127         if (strlen(path) <= 0 || path[0] != '/') {
128                 rc = -EINVAL;
129                 llapi_err_noerrno(LLAPI_MSG_ERROR, "invalid file path: %s",
130                                   path);
131                 return rc;
132         }
133
134         fd = open(path, O_RDONLY);
135         if (fd < 0) {
136                 rc = -errno;
137                 llapi_error(LLAPI_MSG_ERROR, rc, "open file: %s failed",
138                             path);
139                 return rc;
140         }
141
142         rc = llapi_pcc_attach_ro_fd(fd, roid);
143
144         close(fd);
145         return rc;
146 }
147
148 int llapi_pcc_attach(const char *path, __u32 id, enum lu_pcc_type type)
149 {
150         int rc;
151
152         switch (type & LU_PCC_TYPE_MASK) {
153         case LU_PCC_READWRITE:
154                 rc = llapi_pcc_attach_rw(path, id);
155                 break;
156         case LU_PCC_READONLY:
157                 rc = llapi_pcc_attach_ro(path, id);
158                 break;
159         default:
160                 rc = -EINVAL;
161                 break;
162         }
163         return rc;
164 }
165
166 static int llapi_pcc_attach_rw_fid(const char *mntpath,
167                                    const struct lu_fid *fid,
168                                    __u32 rwid)
169 {
170         int rc;
171         int fd;
172
173         fd = llapi_open_by_fid(mntpath, fid, O_RDWR | O_NONBLOCK);
174         if (fd < 0) {
175                 rc = -errno;
176                 llapi_error(LLAPI_MSG_ERROR, rc,
177                             "llapi_open_by_fid for " DFID "failed",
178                             PFID(fid));
179                 return rc;
180         }
181
182         rc = llapi_pcc_attach_rw_fd(fd, rwid);
183
184         close(fd);
185         return rc;
186 }
187
188 static int llapi_pcc_attach_ro_fid(const char *mntpath,
189                                    const struct lu_fid *fid,
190                                    __u32 roid)
191 {
192         int rc;
193         int fd;
194
195         fd = llapi_open_by_fid(mntpath, fid, O_RDONLY);
196         if (fd < 0) {
197                 rc = -errno;
198                 llapi_error(LLAPI_MSG_ERROR, rc,
199                             "llapi_open_by_fid for " DFID "failed",
200                             PFID(fid));
201                 return rc;
202         }
203
204         rc = llapi_pcc_attach_ro_fd(fd, roid);
205
206         close(fd);
207         return rc;
208 }
209
210 int llapi_pcc_attach_fid(const char *mntpath, const struct lu_fid *fid,
211                          __u32 id, enum lu_pcc_type type)
212 {
213         int rc;
214
215         switch (type & LU_PCC_TYPE_MASK) {
216         case LU_PCC_READWRITE:
217                 rc = llapi_pcc_attach_rw_fid(mntpath, fid, id);
218                 break;
219         case LU_PCC_READONLY:
220                 rc = llapi_pcc_attach_ro_fid(mntpath, fid, id);
221                 break;
222         default:
223                 rc = -EINVAL;
224                 break;
225         }
226         return rc;
227 }
228
229
230 int llapi_pcc_attach_fid_str(const char *mntpath, const char *fidstr,
231                              __u32 id, enum lu_pcc_type type)
232 {
233         int rc;
234         struct lu_fid fid;
235         const char *fidstr_orig = fidstr;
236
237         while (*fidstr == '[')
238                 fidstr++;
239         rc = sscanf(fidstr, SFID, RFID(&fid));
240         if (rc != 3) {
241                 llapi_err_noerrno(LLAPI_MSG_ERROR,
242                                   "bad FID format '%s', should be [seq:oid:ver]"
243                                   " (e.g. "DFID")\n", fidstr_orig,
244                                   (unsigned long long)FID_SEQ_NORMAL, 2, 0);
245                 return -EINVAL;
246         }
247
248         rc = llapi_pcc_attach_fid(mntpath, &fid, id, type);
249
250         return rc;
251 }
252
253 /**
254  * detach PCC cache of a file by using fd.
255  *
256  * \param fd            File handle.
257  * \param option        Detach option
258  *
259  * \return 0 on success, an error code otherwise.
260  */
261 int llapi_pcc_detach_fd(int fd, __u32 option)
262 {
263         struct lu_pcc_detach detach;
264         int rc;
265
266         detach.pccd_opt = option;
267         rc = ioctl(fd, LL_IOC_PCC_DETACH, &detach);
268         /* If error, save errno value */
269         rc = rc ? -errno : 0;
270
271         return rc;
272 }
273
274 /**
275  * detach PCC cache of a file via FID.
276  *
277  * \param mntpath       Fullpath to the client mount point.
278  * \param fid           FID of the file.
279  * \param option        Detach option.
280  *
281  * \return 0 on success, an error code otherwise.
282  */
283 int llapi_pcc_detach_fid(const char *mntpath, const struct lu_fid *fid,
284                          __u32 option)
285 {
286         int rc;
287         int fd;
288         struct lu_pcc_detach_fid detach;
289
290         rc = llapi_root_path_open(mntpath, &fd);
291         if (rc) {
292                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get root path: %s",
293                             mntpath);
294                 return rc;
295         }
296
297         /*
298          * PCC prefetching algorithm scans Lustre OPEN/CLOSE changelogs
299          * to determine the candidate files needing to prefetch into
300          * PCC. To avoid generattion of unnecessary open/close changelogs,
301          * we implement a new dir ioctl LL_IOC_PCC_DETACH_BY_FID to detach
302          * files.
303          */
304         detach.pccd_fid = *fid;
305         detach.pccd_opt = option;
306
307         rc = ioctl(fd, LL_IOC_PCC_DETACH_BY_FID, &detach);
308         rc = rc ? -errno : 0;
309
310         close(fd);
311         return rc;
312 }
313
314 /**
315  * detach PCC cache of a file via FID.
316  *
317  * \param mntpath       Fullpath to the client mount point.
318  * \param fidstr        FID string of the file.
319  * \param option        Detach option.
320  *
321  * \return 0 on success, an error code otherwise.
322  */
323 int llapi_pcc_detach_fid_str(const char *mntpath, const char *fidstr,
324                              __u32 option)
325 {
326         int rc;
327         struct lu_fid fid;
328         const char *fidstr_orig = fidstr;
329
330         while (*fidstr == '[')
331                 fidstr++;
332         rc = sscanf(fidstr, SFID, RFID(&fid));
333         if (rc != 3 || !fid_is_sane(&fid)) {
334                 llapi_err_noerrno(LLAPI_MSG_ERROR,
335                                   "bad FID format '%s', should be [seq:oid:ver]"
336                                   " (e.g. "DFID")\n", fidstr_orig,
337                                   (unsigned long long)FID_SEQ_NORMAL, 2, 0);
338                 return -EINVAL;
339         }
340
341         rc = llapi_pcc_detach_fid(mntpath, &fid, option);
342
343         return rc;
344 }
345
346 /**
347  * detach PCC cache of a file.
348  *
349  * \param path          Fullpath to the file to operate on.
350  * \param option        Detach option.
351  *
352  * \return 0 on success, an error code otherwise.
353  */
354 int llapi_pcc_detach_file(const char *path, __u32 option)
355 {
356         int rc;
357         int fd;
358
359         fd = open(path, O_RDWR | O_NONBLOCK);
360         if (fd < 0) {
361                 rc = -errno;
362                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'",
363                             path);
364                 return rc;
365         }
366
367         rc = llapi_pcc_detach_fd(fd, option);
368         close(fd);
369         return rc;
370 }
371
372 /**
373  * Return the current PCC state related to a file.
374  *
375  * \param fd    File handle.
376  * \param state PCC state info.
377  *
378  * \return 0 on success, an error code otherwise.
379  */
380 int llapi_pcc_state_get_fd(int fd, struct lu_pcc_state *state)
381 {
382         int rc;
383
384         rc = ioctl(fd, LL_IOC_PCC_STATE, state);
385         /* If error, save errno value */
386         rc = rc ? -errno : 0;
387
388         return rc;
389 }
390
391 /**
392  * Return the current PCC state related to file pointed by a path.
393  *
394  * see llapi_pcc_state_get_fd() for args use and return
395  */
396 int llapi_pcc_state_get(const char *path, struct lu_pcc_state *state)
397 {
398         int fd;
399         int rc;
400
401         fd = open(path, O_RDONLY | O_NONBLOCK);
402         if (fd < 0)
403                 return -errno;
404
405         rc = llapi_pcc_state_get_fd(fd, state);
406
407         close(fd);
408         return rc;
409 }
410
411 /**
412  * Add/delete a PCC backend on a client.
413  */
414 int llapi_pccdev_set(const char *mntpath, const char *cmd)
415 {
416         char buf[sizeof(struct obd_uuid)];
417         glob_t path;
418         ssize_t count;
419         int fd;
420         int rc;
421
422         rc = llapi_getname(mntpath, buf, sizeof(buf));
423         if (rc < 0) {
424                 llapi_error(LLAPI_MSG_ERROR, rc,
425                             "cannot get name for '%s'", mntpath);
426                 return rc;
427         }
428
429         rc = cfs_get_param_paths(&path, "llite/%s/pcc", buf);
430         if (rc != 0)
431                 return -errno;
432
433         fd = open(path.gl_pathv[0], O_WRONLY);
434         if (fd < 0) {
435                 rc = -errno;
436                 llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s",
437                             path.gl_pathv[0]);
438                 goto out;
439         }
440
441         count = write(fd, cmd, strlen(cmd));
442         if (count < 0) {
443                 rc = errno;
444                 if (errno != EIO)
445                         llapi_error(LLAPI_MSG_ERROR, rc,
446                                     "error: setting llite.%s.pcc='%s'",
447                                     buf, cmd);
448         } else if (count < strlen(cmd)) { /* Truncate case */
449                 rc = -EINVAL;
450                 llapi_error(LLAPI_MSG_ERROR, rc,
451                             "setting llite.%s.pcc='%s': wrote only %zd",
452                             buf, cmd, count);
453         }
454         close(fd);
455 out:
456         cfs_free_param_data(&path);
457         return rc;
458 }
459
460 /**
461  * List all PCC backend devices on a client.
462  */
463 int llapi_pccdev_get(const char *mntpath)
464 {
465         long page_size = sysconf(_SC_PAGESIZE);
466         char pathbuf[sizeof(struct obd_uuid)];
467         glob_t path;
468         char *buf;
469         int fd;
470         int rc;
471
472         rc = llapi_getname(mntpath, pathbuf, sizeof(pathbuf));
473         if (rc < 0) {
474                 llapi_error(LLAPI_MSG_ERROR, rc,
475                             "cannot get name for '%s'", mntpath);
476                 return rc;
477         }
478
479         rc = cfs_get_param_paths(&path, "llite/%s/pcc", pathbuf);
480         if (rc != 0)
481                 return -errno;
482
483         /* Read the contents of file to stdout */
484         fd = open(path.gl_pathv[0], O_RDONLY);
485         if (fd < 0) {
486                 rc = -errno;
487                 llapi_error(LLAPI_MSG_ERROR, rc,
488                             "error: pccdev_get: opening '%s'",
489                             path.gl_pathv[0]);
490                 goto out_free_param;
491         }
492
493         buf = calloc(1, page_size);
494         if (buf == NULL) {
495                 rc = -ENOMEM;
496                 llapi_error(LLAPI_MSG_ERROR, rc,
497                             "error: pccdev_get: allocating '%s' buffer",
498                             path.gl_pathv[0]);
499                 goto out_close;
500         }
501
502         while (1) {
503                 ssize_t count = read(fd, buf, page_size);
504
505                 if (count == 0)
506                         break;
507                 if (count < 0) {
508                         rc = -errno;
509                         if (errno != EIO) {
510                                 llapi_error(LLAPI_MSG_ERROR, rc,
511                                            "error: pccdev_get: reading failed");
512                         }
513                         break;
514                 }
515
516                 if (fwrite(buf, 1, count, stdout) != count) {
517                         rc = -errno;
518                         llapi_error(LLAPI_MSG_ERROR, rc,
519                                     "error: get_param: write to stdout");
520                         break;
521                 }
522         }
523 out_close:
524         close(fd);
525         free(buf);
526 out_free_param:
527         cfs_free_param_data(&path);
528         return rc;
529 }