Whamcloud - gitweb
LU-10092 llite: Add persistent cache on client
[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(const char *path, __u32 archive_id)
49 {
50         int fd;
51         int rc;
52         struct ll_ioc_lease *data;
53
54         fd = open(path, O_RDWR | O_NONBLOCK);
55         if (fd < 0) {
56                 rc = -errno;
57                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'",
58                             path);
59                 return rc;
60         }
61
62         rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
63         if (rc < 0) {
64                 llapi_error(LLAPI_MSG_ERROR, rc,
65                             "cannot get lease for '%s'", path);
66                 goto out_close;
67         }
68
69         data = malloc(offsetof(typeof(*data), lil_ids[1]));
70         if (!data) {
71                 rc = -ENOMEM;
72                 llapi_err_noerrno(LLAPI_MSG_ERROR,
73                                   "failed to allocate memory");
74                 goto out_close;
75         }
76
77         data->lil_mode = LL_LEASE_UNLCK;
78         data->lil_flags = LL_LEASE_PCC_ATTACH;
79         data->lil_count = 1;
80         data->lil_ids[0] = archive_id;
81         rc = llapi_lease_set(fd, data);
82         if (rc <= 0) {
83                 if (rc == 0) /* lost lease lock */
84                         rc = -EBUSY;
85                 llapi_error(LLAPI_MSG_ERROR, rc,
86                             "cannot attach '%s' with ID: %u",
87                              path, archive_id);
88         } else {
89                 rc = 0;
90         }
91
92         free(data);
93 out_close:
94         close(fd);
95         return rc;
96 }
97
98 int llapi_pcc_attach(const char *path, __u32 id, enum lu_pcc_type type)
99 {
100         int rc;
101
102         switch (type) {
103         case LU_PCC_READWRITE:
104                 rc = llapi_readwrite_pcc_attach(path, id);
105                 break;
106         default:
107                 rc = -EINVAL;
108                 break;
109         }
110         return rc;
111 }
112
113
114 /**
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).
117  *
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.
121  *
122  * \param fd            Directory file descriptor.
123  * \param fid           FID of the file.
124  *
125  * \return 0 on success, an error code otherwise.
126  */
127 int llapi_pcc_detach_fid_fd(int fd, const struct lu_fid *fid)
128 {
129         int rc;
130         struct lu_pcc_detach detach;
131
132         detach.pccd_fid = *fid;
133         rc = ioctl(fd, LL_IOC_PCC_DETACH, &detach);
134         if (rc == -EAGAIN)
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));
139         else if (rc)
140                 llapi_error(LLAPI_MSG_ERROR, rc,
141                             "cannot detach FID "DFID" from PCC", PFID(fid));
142
143         return rc;
144 }
145
146 /**
147  * detach PCC cache of a file.
148  *
149  * \param mntpath       Fullpath to the client mount point.
150  * \param fid           FID of the file.
151  *
152  * \return 0 on success, an error code otherwise.
153  */
154 int llapi_pcc_detach_fid(const char *mntpath, const struct lu_fid *fid)
155 {
156         int rc;
157         int fd;
158
159         rc = get_root_path(WANT_FD, NULL, &fd, (char *)mntpath, -1);
160         if (rc) {
161                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get root path: %s",
162                             mntpath);
163                 return rc;
164         }
165
166         rc = llapi_pcc_detach_fid_fd(fd, fid);
167
168         close(fd);
169         return rc;
170 }
171
172 /**
173  * detach PCC cache of a file.
174  *
175  * \param mntpath       Fullpath to the client mount point.
176  * \param fid           FID string of the file.
177  *
178  * \return 0 on success, an error code otherwise.
179  */
180 int llapi_pcc_detach_fid_str(const char *mntpath, const char *fidstr)
181 {
182         int rc;
183         struct lu_fid fid;
184         const char *fidstr_orig = fidstr;
185
186         while (*fidstr == '[')
187                 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);
194                 return -EINVAL;
195         }
196
197         rc = llapi_pcc_detach_fid(mntpath, &fid);
198
199         return rc;
200 }
201
202 /**
203  * detach PCC cache of a file.
204  *
205  * \param path    Fullpath to the file to operate on.
206  *
207  * \return 0 on success, an error code otherwise.
208  */
209 int llapi_pcc_detach_file(const char *path)
210 {
211         int rc;
212         lustre_fid fid;
213
214         rc = llapi_path2fid(path, &fid);
215         if (rc) {
216                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get FID of '%s'",
217                             path);
218                 return rc;
219         }
220
221         rc = llapi_pcc_detach_fid(path, &fid);
222         return rc;
223 }
224
225 /**
226  * Return the current PCC state related to a file.
227  *
228  * \param fd    File handle.
229  * \param state PCC state info.
230  *
231  * \return 0 on success, an error code otherwise.
232  */
233 int llapi_pcc_state_get_fd(int fd, struct lu_pcc_state *state)
234 {
235         int rc;
236
237         rc = ioctl(fd, LL_IOC_PCC_STATE, state);
238         /* If error, save errno value */
239         rc = rc ? -errno : 0;
240
241         return rc;
242 }
243
244 /**
245  * Return the current PCC state related to file pointed by a path.
246  *
247  * see llapi_pcc_state_get_fd() for args use and return
248  */
249 int llapi_pcc_state_get(const char *path, struct lu_pcc_state *state)
250 {
251         int fd;
252         int rc;
253
254         fd = open(path, O_RDONLY | O_NONBLOCK);
255         if (fd < 0)
256                 return -errno;
257
258         rc = llapi_pcc_state_get_fd(fd, state);
259
260         close(fd);
261         return rc;
262 }
263
264 /**
265  * Add/delete a PCC backend on a client.
266  */
267 int llapi_pccdev_set(const char *mntpath, const char *cmd)
268 {
269         char buf[sizeof(struct obd_uuid)];
270         glob_t path;
271         ssize_t count;
272         int fd;
273         int rc;
274
275         rc = llapi_getname(mntpath, buf, sizeof(buf));
276         if (rc < 0) {
277                 llapi_error(LLAPI_MSG_ERROR, rc,
278                             "cannot get name for '%s'\n", mntpath);
279                 return rc;
280         }
281
282         rc = cfs_get_param_paths(&path, "llite/%s/pcc", buf);
283         if (rc != 0)
284                 return -errno;
285
286         fd = open(path.gl_pathv[0], O_WRONLY);
287         if (fd < 0) {
288                 rc = -errno;
289                 llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s",
290                             path.gl_pathv[0]);
291                 goto out;
292         }
293
294         count = write(fd, cmd, strlen(cmd));
295         if (count < 0) {
296                 rc = errno;
297                 if (errno != EIO)
298                         llapi_error(LLAPI_MSG_ERROR, rc,
299                                     "error: setting llite.%s.pcc=\"%s\"\n",
300                                     buf, cmd);
301         } else if (count < strlen(cmd)) { /* Truncate case */
302                 rc = -EINVAL;
303                 llapi_error(LLAPI_MSG_ERROR, rc,
304                             "setting llite.%s.pcc=\"%s\": wrote only %zd\n",
305                             buf, cmd, count);
306         }
307         close(fd);
308 out:
309         cfs_free_param_data(&path);
310         return rc;
311 }
312
313 /**
314  * List all PCC backend devices on a client.
315  */
316 int llapi_pccdev_get(const char *mntpath)
317 {
318         long page_size = sysconf(_SC_PAGESIZE);
319         char pathbuf[sizeof(struct obd_uuid)];
320         glob_t path;
321         char *buf;
322         int fd;
323         int rc;
324
325         rc = llapi_getname(mntpath, pathbuf, sizeof(pathbuf));
326         if (rc < 0) {
327                 llapi_error(LLAPI_MSG_ERROR, rc,
328                             "cannot get name for '%s'\n", mntpath);
329                 return rc;
330         }
331
332         rc = cfs_get_param_paths(&path, "llite/%s/pcc", pathbuf);
333         if (rc != 0)
334                 return -errno;
335
336         /* Read the contents of file to stdout */
337         fd = open(path.gl_pathv[0], O_RDONLY);
338         if (fd < 0) {
339                 rc = -errno;
340                 llapi_error(LLAPI_MSG_ERROR, rc,
341                             "error: pccdev_get: opening '%s'\n",
342                             path.gl_pathv[0]);
343                 goto out_free_param;
344         }
345
346         buf = calloc(1, page_size);
347         if (buf == NULL) {
348                 rc = -ENOMEM;
349                 llapi_error(LLAPI_MSG_ERROR, rc,
350                             "error: pccdev_get: allocating '%s' buffer\n",
351                             path.gl_pathv[0]);
352                 goto out_close;
353         }
354
355         while (1) {
356                 ssize_t count = read(fd, buf, page_size);
357
358                 if (count == 0)
359                         break;
360                 if (count < 0) {
361                         rc = -errno;
362                         if (errno != EIO) {
363                                 llapi_error(LLAPI_MSG_ERROR, rc,
364                                             "error: pccdev_get: "
365                                             "reading failed\n");
366                         }
367                         break;
368                 }
369
370                 if (fwrite(buf, 1, count, stdout) != count) {
371                         rc = -errno;
372                         llapi_error(LLAPI_MSG_ERROR, rc,
373                                     "error: get_param: write to stdout\n");
374                         break;
375                 }
376         }
377 out_close:
378         close(fd);
379         free(buf);
380 out_free_param:
381         cfs_free_param_data(&path);
382         return rc;
383 }