4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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
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.
20 * Copyright (c) 2017, DDN Storage Corporation.
23 * This file is part of Lustre, http://www.lustre.org/
27 * lustreapi library for Persistent Client Cache.
29 * Author: Li Xi <lixi@ddn.com>
30 * Author: Qian Yingjin <qian@ddn.com>
32 #include <sys/types.h>
35 #include <lustre/lustreapi.h>
36 #include <linux/lustre/lustre_user.h>
37 #include <linux/lustre/lustre_fid.h>
41 #include <sys/ioctl.h>
42 #include "lustreapi_internal.h"
45 * Fetch and attach a file to readwrite PCC.
48 static int llapi_pcc_attach_rw_fd(int fd, __u32 archive_id)
51 struct ll_ioc_lease *data;
53 rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
55 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get lease");
59 data = malloc(offsetof(typeof(*data), lil_ids[1]));
62 llapi_err_noerrno(LLAPI_MSG_ERROR,
63 "failed to allocate memory");
67 data->lil_mode = LL_LEASE_UNLCK;
68 data->lil_flags = LL_LEASE_PCC_ATTACH;
70 data->lil_ids[0] = archive_id;
71 rc = llapi_lease_set(fd, data);
73 if (rc == 0) /* lost lease lock */
75 llapi_error(LLAPI_MSG_ERROR, rc,
76 "cannot attach with ID: %u", archive_id);
85 static int llapi_pcc_attach_rw(const char *path, __u32 archive_id)
90 fd = open(path, O_RDWR | O_NONBLOCK);
93 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'",
98 rc = llapi_pcc_attach_rw_fd(fd, archive_id);
104 static int llapi_pcc_attach_ro_fd(int fd, __u32 roid)
106 struct lu_pcc_attach attach;
109 attach.pcca_id = roid;
110 attach.pcca_type = LU_PCC_READONLY;
111 rc = ioctl(fd, LL_IOC_PCC_ATTACH, &attach);
114 llapi_error(LLAPI_MSG_ERROR, rc,
115 "cannot attach the file to PCC with ID %u failed",
122 static int llapi_pcc_attach_ro(const char *path, __u32 roid)
127 if (strlen(path) <= 0 || path[0] != '/') {
129 llapi_err_noerrno(LLAPI_MSG_ERROR, "invalid file path: %s",
134 fd = open(path, O_RDONLY);
137 llapi_error(LLAPI_MSG_ERROR, rc, "open file: %s failed",
142 rc = llapi_pcc_attach_ro_fd(fd, roid);
148 int llapi_pcc_attach(const char *path, __u32 id, enum lu_pcc_type type)
152 switch (type & LU_PCC_TYPE_MASK) {
153 case LU_PCC_READWRITE:
154 rc = llapi_pcc_attach_rw(path, id);
156 case LU_PCC_READONLY:
157 rc = llapi_pcc_attach_ro(path, id);
166 static int llapi_pcc_attach_rw_fid(const char *mntpath,
167 const struct lu_fid *fid,
173 fd = llapi_open_by_fid(mntpath, fid, O_RDWR | O_NONBLOCK);
176 llapi_error(LLAPI_MSG_ERROR, rc,
177 "llapi_open_by_fid for " DFID "failed",
182 rc = llapi_pcc_attach_rw_fd(fd, rwid);
188 static int llapi_pcc_attach_ro_fid(const char *mntpath,
189 const struct lu_fid *fid,
195 fd = llapi_open_by_fid(mntpath, fid, O_RDONLY);
198 llapi_error(LLAPI_MSG_ERROR, rc,
199 "llapi_open_by_fid for " DFID "failed",
204 rc = llapi_pcc_attach_ro_fd(fd, roid);
210 int llapi_pcc_attach_fid(const char *mntpath, const struct lu_fid *fid,
211 __u32 id, enum lu_pcc_type type)
215 switch (type & LU_PCC_TYPE_MASK) {
216 case LU_PCC_READWRITE:
217 rc = llapi_pcc_attach_rw_fid(mntpath, fid, id);
219 case LU_PCC_READONLY:
220 rc = llapi_pcc_attach_ro_fid(mntpath, fid, id);
230 int llapi_pcc_attach_fid_str(const char *mntpath, const char *fidstr,
231 __u32 id, enum lu_pcc_type type)
235 const char *fidstr_orig = fidstr;
237 while (*fidstr == '[')
239 rc = sscanf(fidstr, SFID, RFID(&fid));
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);
248 rc = llapi_pcc_attach_fid(mntpath, &fid, id, type);
254 * detach PCC cache of a file by using fd.
256 * \param fd File handle.
257 * \param option Detach option
259 * \return 0 on success, an error code otherwise.
261 int llapi_pcc_detach_fd(int fd, __u32 option)
263 struct lu_pcc_detach detach;
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;
275 * detach PCC cache of a file via FID.
277 * \param mntpath Fullpath to the client mount point.
278 * \param fid FID of the file.
279 * \param option Detach option.
281 * \return 0 on success, an error code otherwise.
283 int llapi_pcc_detach_fid(const char *mntpath, const struct lu_fid *fid,
288 struct lu_pcc_detach_fid detach;
290 rc = llapi_root_path_open(mntpath, &fd);
292 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get root path: %s",
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
304 detach.pccd_fid = *fid;
305 detach.pccd_opt = option;
307 rc = ioctl(fd, LL_IOC_PCC_DETACH_BY_FID, &detach);
308 rc = rc ? -errno : 0;
315 * detach PCC cache of a file via FID.
317 * \param mntpath Fullpath to the client mount point.
318 * \param fidstr FID string of the file.
319 * \param option Detach option.
321 * \return 0 on success, an error code otherwise.
323 int llapi_pcc_detach_fid_str(const char *mntpath, const char *fidstr,
328 const char *fidstr_orig = fidstr;
330 while (*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);
341 rc = llapi_pcc_detach_fid(mntpath, &fid, option);
347 * detach PCC cache of a file.
349 * \param path Fullpath to the file to operate on.
350 * \param option Detach option.
352 * \return 0 on success, an error code otherwise.
354 int llapi_pcc_detach_file(const char *path, __u32 option)
359 fd = open(path, O_RDWR | O_NONBLOCK);
362 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'",
367 rc = llapi_pcc_detach_fd(fd, option);
373 * Return the current PCC state related to a file.
375 * \param fd File handle.
376 * \param state PCC state info.
378 * \return 0 on success, an error code otherwise.
380 int llapi_pcc_state_get_fd(int fd, struct lu_pcc_state *state)
384 rc = ioctl(fd, LL_IOC_PCC_STATE, state);
385 /* If error, save errno value */
386 rc = rc ? -errno : 0;
392 * Return the current PCC state related to file pointed by a path.
394 * see llapi_pcc_state_get_fd() for args use and return
396 int llapi_pcc_state_get(const char *path, struct lu_pcc_state *state)
401 fd = open(path, O_RDONLY | O_NONBLOCK);
405 rc = llapi_pcc_state_get_fd(fd, state);
412 * Add/delete a PCC backend on a client.
414 int llapi_pccdev_set(const char *mntpath, const char *cmd)
416 char buf[sizeof(struct obd_uuid)];
422 rc = llapi_getname(mntpath, buf, sizeof(buf));
424 llapi_error(LLAPI_MSG_ERROR, rc,
425 "cannot get name for '%s'", mntpath);
429 rc = cfs_get_param_paths(&path, "llite/%s/pcc", buf);
433 fd = open(path.gl_pathv[0], O_WRONLY);
436 llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s",
441 count = write(fd, cmd, strlen(cmd));
445 llapi_error(LLAPI_MSG_ERROR, rc,
446 "error: setting llite.%s.pcc='%s'",
448 } else if (count < strlen(cmd)) { /* Truncate case */
450 llapi_error(LLAPI_MSG_ERROR, rc,
451 "setting llite.%s.pcc='%s': wrote only %zd",
456 cfs_free_param_data(&path);
461 * List all PCC backend devices on a client.
463 int llapi_pccdev_get(const char *mntpath)
465 long page_size = sysconf(_SC_PAGESIZE);
466 char pathbuf[sizeof(struct obd_uuid)];
472 rc = llapi_getname(mntpath, pathbuf, sizeof(pathbuf));
474 llapi_error(LLAPI_MSG_ERROR, rc,
475 "cannot get name for '%s'", mntpath);
479 rc = cfs_get_param_paths(&path, "llite/%s/pcc", pathbuf);
483 /* Read the contents of file to stdout */
484 fd = open(path.gl_pathv[0], O_RDONLY);
487 llapi_error(LLAPI_MSG_ERROR, rc,
488 "error: pccdev_get: opening '%s'",
493 buf = calloc(1, page_size);
496 llapi_error(LLAPI_MSG_ERROR, rc,
497 "error: pccdev_get: allocating '%s' buffer",
503 ssize_t count = read(fd, buf, page_size);
510 llapi_error(LLAPI_MSG_ERROR, rc,
511 "error: pccdev_get: reading failed");
516 if (fwrite(buf, 1, count, stdout) != count) {
518 llapi_error(LLAPI_MSG_ERROR, rc,
519 "error: get_param: write to stdout");
527 cfs_free_param_data(&path);