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_readwrite_pcc_attach(const char *path, __u32 archive_id)
52 struct ll_ioc_lease *data;
54 fd = open(path, O_RDWR | O_NONBLOCK);
57 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'",
62 rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
64 llapi_error(LLAPI_MSG_ERROR, rc,
65 "cannot get lease for '%s'", path);
69 data = malloc(offsetof(typeof(*data), lil_ids[1]));
72 llapi_err_noerrno(LLAPI_MSG_ERROR,
73 "failed to allocate memory");
77 data->lil_mode = LL_LEASE_UNLCK;
78 data->lil_flags = LL_LEASE_PCC_ATTACH;
80 data->lil_ids[0] = archive_id;
81 rc = llapi_lease_set(fd, data);
83 if (rc == 0) /* lost lease lock */
85 llapi_error(LLAPI_MSG_ERROR, rc,
86 "cannot attach '%s' with ID: %u",
98 int llapi_pcc_attach(const char *path, __u32 id, enum lu_pcc_type type)
103 case LU_PCC_READWRITE:
104 rc = llapi_readwrite_pcc_attach(path, id);
115 * detach PCC cache of a file by an ioctl on the dir fd (usually a mount
116 * point fd that the copytool already has open).
118 * If the file is being used, the detaching will return -EBUSY immediately.
119 * Thus, if a PCC-attached file is kept open for a long time, the restore
120 * request will always return failure.
122 * \param fd Directory file descriptor.
123 * \param fid FID of the file.
125 * \return 0 on success, an error code otherwise.
127 int llapi_pcc_detach_fid_fd(int fd, const struct lu_fid *fid)
130 struct lu_pcc_detach detach;
132 detach.pccd_fid = *fid;
133 rc = ioctl(fd, LL_IOC_PCC_DETACH, &detach);
135 llapi_error(LLAPI_MSG_ERROR, rc,
136 "FID "DFID" may be in the attaching state, "
137 "or you may need to re-run the pcc_attach "
138 "to finish the attach process.", PFID(fid));
140 llapi_error(LLAPI_MSG_ERROR, rc,
141 "cannot detach FID "DFID" from PCC", PFID(fid));
147 * detach PCC cache of a file.
149 * \param mntpath Fullpath to the client mount point.
150 * \param fid FID of the file.
152 * \return 0 on success, an error code otherwise.
154 int llapi_pcc_detach_fid(const char *mntpath, const struct lu_fid *fid)
159 rc = get_root_path(WANT_FD, NULL, &fd, (char *)mntpath, -1);
161 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get root path: %s",
166 rc = llapi_pcc_detach_fid_fd(fd, fid);
173 * detach PCC cache of a file.
175 * \param mntpath Fullpath to the client mount point.
176 * \param fid FID string of the file.
178 * \return 0 on success, an error code otherwise.
180 int llapi_pcc_detach_fid_str(const char *mntpath, const char *fidstr)
184 const char *fidstr_orig = fidstr;
186 while (*fidstr == '[')
188 rc = sscanf(fidstr, SFID, RFID(&fid));
189 if (rc != 3 || !fid_is_sane(&fid)) {
190 llapi_err_noerrno(LLAPI_MSG_ERROR,
191 "bad FID format '%s', should be [seq:oid:ver]"
192 " (e.g. "DFID")\n", fidstr_orig,
193 (unsigned long long)FID_SEQ_NORMAL, 2, 0);
197 rc = llapi_pcc_detach_fid(mntpath, &fid);
203 * detach PCC cache of a file.
205 * \param path Fullpath to the file to operate on.
207 * \return 0 on success, an error code otherwise.
209 int llapi_pcc_detach_file(const char *path)
214 rc = llapi_path2fid(path, &fid);
216 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get FID of '%s'",
221 rc = llapi_pcc_detach_fid(path, &fid);
226 * Return the current PCC state related to a file.
228 * \param fd File handle.
229 * \param state PCC state info.
231 * \return 0 on success, an error code otherwise.
233 int llapi_pcc_state_get_fd(int fd, struct lu_pcc_state *state)
237 rc = ioctl(fd, LL_IOC_PCC_STATE, state);
238 /* If error, save errno value */
239 rc = rc ? -errno : 0;
245 * Return the current PCC state related to file pointed by a path.
247 * see llapi_pcc_state_get_fd() for args use and return
249 int llapi_pcc_state_get(const char *path, struct lu_pcc_state *state)
254 fd = open(path, O_RDONLY | O_NONBLOCK);
258 rc = llapi_pcc_state_get_fd(fd, state);
265 * Add/delete a PCC backend on a client.
267 int llapi_pccdev_set(const char *mntpath, const char *cmd)
269 char buf[sizeof(struct obd_uuid)];
275 rc = llapi_getname(mntpath, buf, sizeof(buf));
277 llapi_error(LLAPI_MSG_ERROR, rc,
278 "cannot get name for '%s'\n", mntpath);
282 rc = cfs_get_param_paths(&path, "llite/%s/pcc", buf);
286 fd = open(path.gl_pathv[0], O_WRONLY);
289 llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s",
294 count = write(fd, cmd, strlen(cmd));
298 llapi_error(LLAPI_MSG_ERROR, rc,
299 "error: setting llite.%s.pcc=\"%s\"\n",
301 } else if (count < strlen(cmd)) { /* Truncate case */
303 llapi_error(LLAPI_MSG_ERROR, rc,
304 "setting llite.%s.pcc=\"%s\": wrote only %zd\n",
309 cfs_free_param_data(&path);
314 * List all PCC backend devices on a client.
316 int llapi_pccdev_get(const char *mntpath)
318 long page_size = sysconf(_SC_PAGESIZE);
319 char pathbuf[sizeof(struct obd_uuid)];
325 rc = llapi_getname(mntpath, pathbuf, sizeof(pathbuf));
327 llapi_error(LLAPI_MSG_ERROR, rc,
328 "cannot get name for '%s'\n", mntpath);
332 rc = cfs_get_param_paths(&path, "llite/%s/pcc", pathbuf);
336 /* Read the contents of file to stdout */
337 fd = open(path.gl_pathv[0], O_RDONLY);
340 llapi_error(LLAPI_MSG_ERROR, rc,
341 "error: pccdev_get: opening '%s'\n",
346 buf = calloc(1, page_size);
349 llapi_error(LLAPI_MSG_ERROR, rc,
350 "error: pccdev_get: allocating '%s' buffer\n",
356 ssize_t count = read(fd, buf, page_size);
363 llapi_error(LLAPI_MSG_ERROR, rc,
364 "error: pccdev_get: "
370 if (fwrite(buf, 1, count, stdout) != count) {
372 llapi_error(LLAPI_MSG_ERROR, rc,
373 "error: get_param: write to stdout\n");
381 cfs_free_param_data(&path);