Whamcloud - gitweb
LU-16313 pcc: use two bits to indicate pcc type for attach
[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_readwrite_pcc_attach_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_readwrite_pcc_attach(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_readwrite_pcc_attach_fd(fd, archive_id);
99
100         close(fd);
101         return rc;
102 }
103
104 int llapi_pcc_attach(const char *path, __u32 id, enum lu_pcc_type type)
105 {
106         int rc;
107
108         switch (type & LU_PCC_TYPE_MASK) {
109         case LU_PCC_READWRITE:
110                 rc = llapi_readwrite_pcc_attach(path, id);
111                 break;
112         default:
113                 rc = -EINVAL;
114                 break;
115         }
116         return rc;
117 }
118
119 static int llapi_readwrite_pcc_attach_fid(const char *mntpath,
120                                           const struct lu_fid *fid,
121                                           __u32 id)
122 {
123         int rc;
124         int fd;
125
126         fd = llapi_open_by_fid(mntpath, fid, O_RDWR | O_NONBLOCK);
127         if (fd < 0) {
128                 rc = -errno;
129                 llapi_error(LLAPI_MSG_ERROR, rc,
130                             "llapi_open_by_fid for " DFID "failed",
131                             PFID(fid));
132                 return rc;
133         }
134
135         rc = llapi_readwrite_pcc_attach_fd(fd, id);
136
137         close(fd);
138         return rc;
139 }
140
141 int llapi_pcc_attach_fid(const char *mntpath, const struct lu_fid *fid,
142                          __u32 id, enum lu_pcc_type type)
143 {
144         int rc;
145
146         switch (type & LU_PCC_TYPE_MASK) {
147         case LU_PCC_READWRITE:
148                 rc = llapi_readwrite_pcc_attach_fid(mntpath, fid, id);
149                 break;
150         default:
151                 rc = -EINVAL;
152                 break;
153         }
154         return rc;
155 }
156
157
158 int llapi_pcc_attach_fid_str(const char *mntpath, const char *fidstr,
159                              __u32 id, enum lu_pcc_type type)
160 {
161         int rc;
162         struct lu_fid fid;
163         const char *fidstr_orig = fidstr;
164
165         while (*fidstr == '[')
166                 fidstr++;
167         rc = sscanf(fidstr, SFID, RFID(&fid));
168         if (rc != 3) {
169                 llapi_err_noerrno(LLAPI_MSG_ERROR,
170                                   "bad FID format '%s', should be [seq:oid:ver]"
171                                   " (e.g. "DFID")\n", fidstr_orig,
172                                   (unsigned long long)FID_SEQ_NORMAL, 2, 0);
173                 return -EINVAL;
174         }
175
176         rc = llapi_pcc_attach_fid(mntpath, &fid, id, type);
177
178         return rc;
179 }
180
181 /**
182  * detach PCC cache of a file by using fd.
183  *
184  * \param fd            File handle.
185  * \param option        Detach option
186  *
187  * \return 0 on success, an error code otherwise.
188  */
189 int llapi_pcc_detach_fd(int fd, __u32 option)
190 {
191         struct lu_pcc_detach detach;
192         int rc;
193
194         detach.pccd_opt = option;
195         rc = ioctl(fd, LL_IOC_PCC_DETACH, &detach);
196         /* If error, save errno value */
197         rc = rc ? -errno : 0;
198
199         return rc;
200 }
201
202 /**
203  * detach PCC cache of a file via FID.
204  *
205  * \param mntpath       Fullpath to the client mount point.
206  * \param fid           FID of the file.
207  * \param option        Detach option.
208  *
209  * \return 0 on success, an error code otherwise.
210  */
211 int llapi_pcc_detach_fid(const char *mntpath, const struct lu_fid *fid,
212                          __u32 option)
213 {
214         int rc;
215         int fd;
216         struct lu_pcc_detach_fid detach;
217
218         rc = get_root_path(WANT_FD, NULL, &fd, (char *)mntpath, -1, NULL, NULL);
219         if (rc) {
220                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get root path: %s",
221                             mntpath);
222                 return rc;
223         }
224
225         /*
226          * PCC prefetching algorithm scans Lustre OPEN/CLOSE changelogs
227          * to determine the candidate files needing to prefetch into
228          * PCC. To avoid generattion of unnecessary open/close changelogs,
229          * we implement a new dir ioctl LL_IOC_PCC_DETACH_BY_FID to detach
230          * files.
231          */
232         detach.pccd_fid = *fid;
233         detach.pccd_opt = option;
234
235         /* fd is cached internally, no need to close */
236         rc = ioctl(fd, LL_IOC_PCC_DETACH_BY_FID, &detach);
237         rc = rc ? -errno : 0;
238
239         return rc;
240 }
241
242 /**
243  * detach PCC cache of a file via FID.
244  *
245  * \param mntpath       Fullpath to the client mount point.
246  * \param fidstr        FID string of the file.
247  * \param option        Detach option.
248  *
249  * \return 0 on success, an error code otherwise.
250  */
251 int llapi_pcc_detach_fid_str(const char *mntpath, const char *fidstr,
252                              __u32 option)
253 {
254         int rc;
255         struct lu_fid fid;
256         const char *fidstr_orig = fidstr;
257
258         while (*fidstr == '[')
259                 fidstr++;
260         rc = sscanf(fidstr, SFID, RFID(&fid));
261         if (rc != 3 || !fid_is_sane(&fid)) {
262                 llapi_err_noerrno(LLAPI_MSG_ERROR,
263                                   "bad FID format '%s', should be [seq:oid:ver]"
264                                   " (e.g. "DFID")\n", fidstr_orig,
265                                   (unsigned long long)FID_SEQ_NORMAL, 2, 0);
266                 return -EINVAL;
267         }
268
269         rc = llapi_pcc_detach_fid(mntpath, &fid, option);
270
271         return rc;
272 }
273
274 /**
275  * detach PCC cache of a file.
276  *
277  * \param path          Fullpath to the file to operate on.
278  * \param option        Detach option.
279  *
280  * \return 0 on success, an error code otherwise.
281  */
282 int llapi_pcc_detach_file(const char *path, __u32 option)
283 {
284         int rc;
285         int fd;
286
287         fd = open(path, O_RDWR | O_NONBLOCK);
288         if (fd < 0) {
289                 rc = -errno;
290                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'",
291                             path);
292                 return rc;
293         }
294
295         rc = llapi_pcc_detach_fd(fd, option);
296         close(fd);
297         return rc;
298 }
299
300 /**
301  * Return the current PCC state related to a file.
302  *
303  * \param fd    File handle.
304  * \param state PCC state info.
305  *
306  * \return 0 on success, an error code otherwise.
307  */
308 int llapi_pcc_state_get_fd(int fd, struct lu_pcc_state *state)
309 {
310         int rc;
311
312         rc = ioctl(fd, LL_IOC_PCC_STATE, state);
313         /* If error, save errno value */
314         rc = rc ? -errno : 0;
315
316         return rc;
317 }
318
319 /**
320  * Return the current PCC state related to file pointed by a path.
321  *
322  * see llapi_pcc_state_get_fd() for args use and return
323  */
324 int llapi_pcc_state_get(const char *path, struct lu_pcc_state *state)
325 {
326         int fd;
327         int rc;
328
329         fd = open(path, O_RDONLY | O_NONBLOCK);
330         if (fd < 0)
331                 return -errno;
332
333         rc = llapi_pcc_state_get_fd(fd, state);
334
335         close(fd);
336         return rc;
337 }
338
339 /**
340  * Add/delete a PCC backend on a client.
341  */
342 int llapi_pccdev_set(const char *mntpath, const char *cmd)
343 {
344         char buf[sizeof(struct obd_uuid)];
345         glob_t path;
346         ssize_t count;
347         int fd;
348         int rc;
349
350         rc = llapi_getname(mntpath, buf, sizeof(buf));
351         if (rc < 0) {
352                 llapi_error(LLAPI_MSG_ERROR, rc,
353                             "cannot get name for '%s'", mntpath);
354                 return rc;
355         }
356
357         rc = cfs_get_param_paths(&path, "llite/%s/pcc", buf);
358         if (rc != 0)
359                 return -errno;
360
361         fd = open(path.gl_pathv[0], O_WRONLY);
362         if (fd < 0) {
363                 rc = -errno;
364                 llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s",
365                             path.gl_pathv[0]);
366                 goto out;
367         }
368
369         count = write(fd, cmd, strlen(cmd));
370         if (count < 0) {
371                 rc = errno;
372                 if (errno != EIO)
373                         llapi_error(LLAPI_MSG_ERROR, rc,
374                                     "error: setting llite.%s.pcc='%s'",
375                                     buf, cmd);
376         } else if (count < strlen(cmd)) { /* Truncate case */
377                 rc = -EINVAL;
378                 llapi_error(LLAPI_MSG_ERROR, rc,
379                             "setting llite.%s.pcc='%s': wrote only %zd",
380                             buf, cmd, count);
381         }
382         close(fd);
383 out:
384         cfs_free_param_data(&path);
385         return rc;
386 }
387
388 /**
389  * List all PCC backend devices on a client.
390  */
391 int llapi_pccdev_get(const char *mntpath)
392 {
393         long page_size = sysconf(_SC_PAGESIZE);
394         char pathbuf[sizeof(struct obd_uuid)];
395         glob_t path;
396         char *buf;
397         int fd;
398         int rc;
399
400         rc = llapi_getname(mntpath, pathbuf, sizeof(pathbuf));
401         if (rc < 0) {
402                 llapi_error(LLAPI_MSG_ERROR, rc,
403                             "cannot get name for '%s'", mntpath);
404                 return rc;
405         }
406
407         rc = cfs_get_param_paths(&path, "llite/%s/pcc", pathbuf);
408         if (rc != 0)
409                 return -errno;
410
411         /* Read the contents of file to stdout */
412         fd = open(path.gl_pathv[0], O_RDONLY);
413         if (fd < 0) {
414                 rc = -errno;
415                 llapi_error(LLAPI_MSG_ERROR, rc,
416                             "error: pccdev_get: opening '%s'",
417                             path.gl_pathv[0]);
418                 goto out_free_param;
419         }
420
421         buf = calloc(1, page_size);
422         if (buf == NULL) {
423                 rc = -ENOMEM;
424                 llapi_error(LLAPI_MSG_ERROR, rc,
425                             "error: pccdev_get: allocating '%s' buffer",
426                             path.gl_pathv[0]);
427                 goto out_close;
428         }
429
430         while (1) {
431                 ssize_t count = read(fd, buf, page_size);
432
433                 if (count == 0)
434                         break;
435                 if (count < 0) {
436                         rc = -errno;
437                         if (errno != EIO) {
438                                 llapi_error(LLAPI_MSG_ERROR, rc,
439                                            "error: pccdev_get: reading failed");
440                         }
441                         break;
442                 }
443
444                 if (fwrite(buf, 1, count, stdout) != count) {
445                         rc = -errno;
446                         llapi_error(LLAPI_MSG_ERROR, rc,
447                                     "error: get_param: write to stdout");
448                         break;
449                 }
450         }
451 out_close:
452         close(fd);
453         free(buf);
454 out_free_param:
455         cfs_free_param_data(&path);
456         return rc;
457 }