Whamcloud - gitweb
LU-11213 uapi: Remove unused CONNECT flag
[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) {
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) {
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         return rc;
197 }
198
199 /**
200  * detach PCC cache of a file via FID.
201  *
202  * \param mntpath       Fullpath to the client mount point.
203  * \param fid           FID of the file.
204  * \param option        Detach option.
205  *
206  * \return 0 on success, an error code otherwise.
207  */
208 int llapi_pcc_detach_fid(const char *mntpath, const struct lu_fid *fid,
209                          __u32 option)
210 {
211         int rc;
212         int fd;
213         struct lu_pcc_detach_fid detach;
214
215         rc = get_root_path(WANT_FD, NULL, &fd, (char *)mntpath, -1);
216         if (rc) {
217                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get root path: %s",
218                             mntpath);
219                 return rc;
220         }
221
222         /*
223          * PCC prefetching algorithm scans Lustre OPEN/CLOSE changelogs
224          * to determine the candidate files needing to prefetch into
225          * PCC. To avoid generattion of unnecessary open/close changelogs,
226          * we implement a new dir ioctl LL_IOC_PCC_DETACH_BY_FID to detach
227          * files.
228          */
229         detach.pccd_fid = *fid;
230         detach.pccd_opt = option;
231         rc = ioctl(fd, LL_IOC_PCC_DETACH_BY_FID, &detach);
232         close(fd);
233         return rc;
234 }
235
236 /**
237  * detach PCC cache of a file via FID.
238  *
239  * \param mntpath       Fullpath to the client mount point.
240  * \param fidstr        FID string of the file.
241  * \param option        Detach option.
242  *
243  * \return 0 on success, an error code otherwise.
244  */
245 int llapi_pcc_detach_fid_str(const char *mntpath, const char *fidstr,
246                              __u32 option)
247 {
248         int rc;
249         struct lu_fid fid;
250         const char *fidstr_orig = fidstr;
251
252         while (*fidstr == '[')
253                 fidstr++;
254         rc = sscanf(fidstr, SFID, RFID(&fid));
255         if (rc != 3 || !fid_is_sane(&fid)) {
256                 llapi_err_noerrno(LLAPI_MSG_ERROR,
257                                   "bad FID format '%s', should be [seq:oid:ver]"
258                                   " (e.g. "DFID")\n", fidstr_orig,
259                                   (unsigned long long)FID_SEQ_NORMAL, 2, 0);
260                 return -EINVAL;
261         }
262
263         rc = llapi_pcc_detach_fid(mntpath, &fid, option);
264
265         return rc;
266 }
267
268 /**
269  * detach PCC cache of a file.
270  *
271  * \param path          Fullpath to the file to operate on.
272  * \param option        Detach option.
273  *
274  * \return 0 on success, an error code otherwise.
275  */
276 int llapi_pcc_detach_file(const char *path, __u32 option)
277 {
278         int rc;
279         int fd;
280
281         fd = open(path, O_RDWR | O_NONBLOCK);
282         if (fd < 0) {
283                 rc = -errno;
284                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'",
285                             path);
286                 return rc;
287         }
288
289         rc = llapi_pcc_detach_fd(fd, option);
290         close(fd);
291         return rc;
292 }
293
294 /**
295  * Return the current PCC state related to a file.
296  *
297  * \param fd    File handle.
298  * \param state PCC state info.
299  *
300  * \return 0 on success, an error code otherwise.
301  */
302 int llapi_pcc_state_get_fd(int fd, struct lu_pcc_state *state)
303 {
304         int rc;
305
306         rc = ioctl(fd, LL_IOC_PCC_STATE, state);
307         /* If error, save errno value */
308         rc = rc ? -errno : 0;
309
310         return rc;
311 }
312
313 /**
314  * Return the current PCC state related to file pointed by a path.
315  *
316  * see llapi_pcc_state_get_fd() for args use and return
317  */
318 int llapi_pcc_state_get(const char *path, struct lu_pcc_state *state)
319 {
320         int fd;
321         int rc;
322
323         fd = open(path, O_RDONLY | O_NONBLOCK);
324         if (fd < 0)
325                 return -errno;
326
327         rc = llapi_pcc_state_get_fd(fd, state);
328
329         close(fd);
330         return rc;
331 }
332
333 /**
334  * Add/delete a PCC backend on a client.
335  */
336 int llapi_pccdev_set(const char *mntpath, const char *cmd)
337 {
338         char buf[sizeof(struct obd_uuid)];
339         glob_t path;
340         ssize_t count;
341         int fd;
342         int rc;
343
344         rc = llapi_getname(mntpath, buf, sizeof(buf));
345         if (rc < 0) {
346                 llapi_error(LLAPI_MSG_ERROR, rc,
347                             "cannot get name for '%s'\n", mntpath);
348                 return rc;
349         }
350
351         rc = cfs_get_param_paths(&path, "llite/%s/pcc", buf);
352         if (rc != 0)
353                 return -errno;
354
355         fd = open(path.gl_pathv[0], O_WRONLY);
356         if (fd < 0) {
357                 rc = -errno;
358                 llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s",
359                             path.gl_pathv[0]);
360                 goto out;
361         }
362
363         count = write(fd, cmd, strlen(cmd));
364         if (count < 0) {
365                 rc = errno;
366                 if (errno != EIO)
367                         llapi_error(LLAPI_MSG_ERROR, rc,
368                                     "error: setting llite.%s.pcc=\"%s\"\n",
369                                     buf, cmd);
370         } else if (count < strlen(cmd)) { /* Truncate case */
371                 rc = -EINVAL;
372                 llapi_error(LLAPI_MSG_ERROR, rc,
373                             "setting llite.%s.pcc=\"%s\": wrote only %zd\n",
374                             buf, cmd, count);
375         }
376         close(fd);
377 out:
378         cfs_free_param_data(&path);
379         return rc;
380 }
381
382 /**
383  * List all PCC backend devices on a client.
384  */
385 int llapi_pccdev_get(const char *mntpath)
386 {
387         long page_size = sysconf(_SC_PAGESIZE);
388         char pathbuf[sizeof(struct obd_uuid)];
389         glob_t path;
390         char *buf;
391         int fd;
392         int rc;
393
394         rc = llapi_getname(mntpath, pathbuf, sizeof(pathbuf));
395         if (rc < 0) {
396                 llapi_error(LLAPI_MSG_ERROR, rc,
397                             "cannot get name for '%s'\n", mntpath);
398                 return rc;
399         }
400
401         rc = cfs_get_param_paths(&path, "llite/%s/pcc", pathbuf);
402         if (rc != 0)
403                 return -errno;
404
405         /* Read the contents of file to stdout */
406         fd = open(path.gl_pathv[0], O_RDONLY);
407         if (fd < 0) {
408                 rc = -errno;
409                 llapi_error(LLAPI_MSG_ERROR, rc,
410                             "error: pccdev_get: opening '%s'\n",
411                             path.gl_pathv[0]);
412                 goto out_free_param;
413         }
414
415         buf = calloc(1, page_size);
416         if (buf == NULL) {
417                 rc = -ENOMEM;
418                 llapi_error(LLAPI_MSG_ERROR, rc,
419                             "error: pccdev_get: allocating '%s' buffer\n",
420                             path.gl_pathv[0]);
421                 goto out_close;
422         }
423
424         while (1) {
425                 ssize_t count = read(fd, buf, page_size);
426
427                 if (count == 0)
428                         break;
429                 if (count < 0) {
430                         rc = -errno;
431                         if (errno != EIO) {
432                                 llapi_error(LLAPI_MSG_ERROR, rc,
433                                             "error: pccdev_get: "
434                                             "reading failed\n");
435                         }
436                         break;
437                 }
438
439                 if (fwrite(buf, 1, count, stdout) != count) {
440                         rc = -errno;
441                         llapi_error(LLAPI_MSG_ERROR, rc,
442                                     "error: get_param: write to stdout\n");
443                         break;
444                 }
445         }
446 out_close:
447         close(fd);
448         free(buf);
449 out_free_param:
450         cfs_free_param_data(&path);
451         return rc;
452 }