]> Git Repo - J-linux.git/blob - fs/xfs/xfs_handle.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / fs / xfs / xfs_handle.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2000-2005 Silicon Graphics, Inc.
4  * Copyright (c) 2022-2024 Oracle.
5  * All rights reserved.
6  */
7 #include "xfs.h"
8 #include "xfs_fs.h"
9 #include "xfs_format.h"
10 #include "xfs_log_format.h"
11 #include "xfs_shared.h"
12 #include "xfs_trans_resv.h"
13 #include "xfs_mount.h"
14 #include "xfs_bmap_btree.h"
15 #include "xfs_inode.h"
16 #include "xfs_error.h"
17 #include "xfs_trace.h"
18 #include "xfs_trans.h"
19 #include "xfs_da_format.h"
20 #include "xfs_da_btree.h"
21 #include "xfs_attr.h"
22 #include "xfs_ioctl.h"
23 #include "xfs_parent.h"
24 #include "xfs_handle.h"
25 #include "xfs_health.h"
26 #include "xfs_icache.h"
27 #include "xfs_export.h"
28 #include "xfs_xattr.h"
29 #include "xfs_acl.h"
30
31 #include <linux/namei.h>
32
33 static inline size_t
34 xfs_filehandle_fid_len(void)
35 {
36         struct xfs_handle       *handle = NULL;
37
38         return sizeof(struct xfs_fid) - sizeof(handle->ha_fid.fid_len);
39 }
40
41 static inline size_t
42 xfs_filehandle_init(
43         struct xfs_mount        *mp,
44         xfs_ino_t               ino,
45         uint32_t                gen,
46         struct xfs_handle       *handle)
47 {
48         memcpy(&handle->ha_fsid, mp->m_fixedfsid, sizeof(struct xfs_fsid));
49
50         handle->ha_fid.fid_len = xfs_filehandle_fid_len();
51         handle->ha_fid.fid_pad = 0;
52         handle->ha_fid.fid_gen = gen;
53         handle->ha_fid.fid_ino = ino;
54
55         return sizeof(struct xfs_handle);
56 }
57
58 static inline size_t
59 xfs_fshandle_init(
60         struct xfs_mount        *mp,
61         struct xfs_handle       *handle)
62 {
63         memcpy(&handle->ha_fsid, mp->m_fixedfsid, sizeof(struct xfs_fsid));
64         memset(&handle->ha_fid, 0, sizeof(handle->ha_fid));
65
66         return sizeof(struct xfs_fsid);
67 }
68
69 /*
70  * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to
71  * a file or fs handle.
72  *
73  * XFS_IOC_PATH_TO_FSHANDLE
74  *    returns fs handle for a mount point or path within that mount point
75  * XFS_IOC_FD_TO_HANDLE
76  *    returns full handle for a FD opened in user space
77  * XFS_IOC_PATH_TO_HANDLE
78  *    returns full handle for a path
79  */
80 int
81 xfs_find_handle(
82         unsigned int            cmd,
83         xfs_fsop_handlereq_t    *hreq)
84 {
85         int                     hsize;
86         xfs_handle_t            handle;
87         struct inode            *inode;
88         struct path             path;
89         int                     error;
90         struct xfs_inode        *ip;
91
92         if (cmd == XFS_IOC_FD_TO_HANDLE) {
93                 CLASS(fd, f)(hreq->fd);
94
95                 if (fd_empty(f))
96                         return -EBADF;
97                 path = fd_file(f)->f_path;
98                 path_get(&path);
99         } else {
100                 error = user_path_at(AT_FDCWD, hreq->path, 0, &path);
101                 if (error)
102                         return error;
103         }
104         inode = d_inode(path.dentry);
105         ip = XFS_I(inode);
106
107         /*
108          * We can only generate handles for inodes residing on a XFS filesystem,
109          * and only for regular files, directories or symbolic links.
110          */
111         error = -EINVAL;
112         if (inode->i_sb->s_magic != XFS_SB_MAGIC)
113                 goto out_put;
114
115         error = -EBADF;
116         if (!S_ISREG(inode->i_mode) &&
117             !S_ISDIR(inode->i_mode) &&
118             !S_ISLNK(inode->i_mode))
119                 goto out_put;
120
121
122         memcpy(&handle.ha_fsid, ip->i_mount->m_fixedfsid, sizeof(xfs_fsid_t));
123
124         if (cmd == XFS_IOC_PATH_TO_FSHANDLE)
125                 hsize = xfs_fshandle_init(ip->i_mount, &handle);
126         else
127                 hsize = xfs_filehandle_init(ip->i_mount, ip->i_ino,
128                                 inode->i_generation, &handle);
129
130         error = -EFAULT;
131         if (copy_to_user(hreq->ohandle, &handle, hsize) ||
132             copy_to_user(hreq->ohandlen, &hsize, sizeof(__s32)))
133                 goto out_put;
134
135         error = 0;
136
137  out_put:
138         path_put(&path);
139         return error;
140 }
141
142 /*
143  * No need to do permission checks on the various pathname components
144  * as the handle operations are privileged.
145  */
146 STATIC int
147 xfs_handle_acceptable(
148         void                    *context,
149         struct dentry           *dentry)
150 {
151         return 1;
152 }
153
154 /* Convert handle already copied to kernel space into a dentry. */
155 static struct dentry *
156 xfs_khandle_to_dentry(
157         struct file             *file,
158         struct xfs_handle       *handle)
159 {
160         struct xfs_fid64        fid = {
161                 .ino            = handle->ha_fid.fid_ino,
162                 .gen            = handle->ha_fid.fid_gen,
163         };
164
165         /*
166          * Only allow handle opens under a directory.
167          */
168         if (!S_ISDIR(file_inode(file)->i_mode))
169                 return ERR_PTR(-ENOTDIR);
170
171         if (handle->ha_fid.fid_len != xfs_filehandle_fid_len())
172                 return ERR_PTR(-EINVAL);
173
174         return exportfs_decode_fh(file->f_path.mnt, (struct fid *)&fid, 3,
175                         FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG,
176                         xfs_handle_acceptable, NULL);
177 }
178
179 /* Convert handle already copied to kernel space into an xfs_inode. */
180 static struct xfs_inode *
181 xfs_khandle_to_inode(
182         struct file             *file,
183         struct xfs_handle       *handle)
184 {
185         struct xfs_inode        *ip = XFS_I(file_inode(file));
186         struct xfs_mount        *mp = ip->i_mount;
187         struct inode            *inode;
188
189         if (!S_ISDIR(VFS_I(ip)->i_mode))
190                 return ERR_PTR(-ENOTDIR);
191
192         if (handle->ha_fid.fid_len != xfs_filehandle_fid_len())
193                 return ERR_PTR(-EINVAL);
194
195         inode = xfs_nfs_get_inode(mp->m_super, handle->ha_fid.fid_ino,
196                         handle->ha_fid.fid_gen);
197         if (IS_ERR(inode))
198                 return ERR_CAST(inode);
199
200         return XFS_I(inode);
201 }
202
203 /*
204  * Convert userspace handle data into a dentry.
205  */
206 struct dentry *
207 xfs_handle_to_dentry(
208         struct file             *parfilp,
209         void __user             *uhandle,
210         u32                     hlen)
211 {
212         xfs_handle_t            handle;
213
214         if (hlen != sizeof(xfs_handle_t))
215                 return ERR_PTR(-EINVAL);
216         if (copy_from_user(&handle, uhandle, hlen))
217                 return ERR_PTR(-EFAULT);
218
219         return xfs_khandle_to_dentry(parfilp, &handle);
220 }
221
222 STATIC struct dentry *
223 xfs_handlereq_to_dentry(
224         struct file             *parfilp,
225         xfs_fsop_handlereq_t    *hreq)
226 {
227         return xfs_handle_to_dentry(parfilp, hreq->ihandle, hreq->ihandlen);
228 }
229
230 int
231 xfs_open_by_handle(
232         struct file             *parfilp,
233         xfs_fsop_handlereq_t    *hreq)
234 {
235         const struct cred       *cred = current_cred();
236         int                     error;
237         int                     fd;
238         int                     permflag;
239         struct file             *filp;
240         struct inode            *inode;
241         struct dentry           *dentry;
242         fmode_t                 fmode;
243         struct path             path;
244
245         if (!capable(CAP_SYS_ADMIN))
246                 return -EPERM;
247
248         dentry = xfs_handlereq_to_dentry(parfilp, hreq);
249         if (IS_ERR(dentry))
250                 return PTR_ERR(dentry);
251         inode = d_inode(dentry);
252
253         /* Restrict xfs_open_by_handle to directories & regular files. */
254         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
255                 error = -EPERM;
256                 goto out_dput;
257         }
258
259 #if BITS_PER_LONG != 32
260         hreq->oflags |= O_LARGEFILE;
261 #endif
262
263         permflag = hreq->oflags;
264         fmode = OPEN_FMODE(permflag);
265         if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) &&
266             (fmode & FMODE_WRITE) && IS_APPEND(inode)) {
267                 error = -EPERM;
268                 goto out_dput;
269         }
270
271         if ((fmode & FMODE_WRITE) && IS_IMMUTABLE(inode)) {
272                 error = -EPERM;
273                 goto out_dput;
274         }
275
276         /* Can't write directories. */
277         if (S_ISDIR(inode->i_mode) && (fmode & FMODE_WRITE)) {
278                 error = -EISDIR;
279                 goto out_dput;
280         }
281
282         fd = get_unused_fd_flags(0);
283         if (fd < 0) {
284                 error = fd;
285                 goto out_dput;
286         }
287
288         path.mnt = parfilp->f_path.mnt;
289         path.dentry = dentry;
290         filp = dentry_open(&path, hreq->oflags, cred);
291         dput(dentry);
292         if (IS_ERR(filp)) {
293                 put_unused_fd(fd);
294                 return PTR_ERR(filp);
295         }
296
297         if (S_ISREG(inode->i_mode)) {
298                 filp->f_flags |= O_NOATIME;
299                 filp->f_mode |= FMODE_NOCMTIME;
300         }
301
302         fd_install(fd, filp);
303         return fd;
304
305  out_dput:
306         dput(dentry);
307         return error;
308 }
309
310 int
311 xfs_readlink_by_handle(
312         struct file             *parfilp,
313         xfs_fsop_handlereq_t    *hreq)
314 {
315         struct dentry           *dentry;
316         __u32                   olen;
317         int                     error;
318
319         if (!capable(CAP_SYS_ADMIN))
320                 return -EPERM;
321
322         dentry = xfs_handlereq_to_dentry(parfilp, hreq);
323         if (IS_ERR(dentry))
324                 return PTR_ERR(dentry);
325
326         /* Restrict this handle operation to symlinks only. */
327         if (!d_is_symlink(dentry)) {
328                 error = -EINVAL;
329                 goto out_dput;
330         }
331
332         if (copy_from_user(&olen, hreq->ohandlen, sizeof(__u32))) {
333                 error = -EFAULT;
334                 goto out_dput;
335         }
336
337         error = vfs_readlink(dentry, hreq->ohandle, olen);
338
339  out_dput:
340         dput(dentry);
341         return error;
342 }
343
344 /*
345  * Format an attribute and copy it out to the user's buffer.
346  * Take care to check values and protect against them changing later,
347  * we may be reading them directly out of a user buffer.
348  */
349 static void
350 xfs_ioc_attr_put_listent(
351         struct xfs_attr_list_context *context,
352         int                     flags,
353         unsigned char           *name,
354         int                     namelen,
355         void                    *value,
356         int                     valuelen)
357 {
358         struct xfs_attrlist     *alist = context->buffer;
359         struct xfs_attrlist_ent *aep;
360         int                     arraytop;
361
362         ASSERT(!context->seen_enough);
363         ASSERT(context->count >= 0);
364         ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
365         ASSERT(context->firstu >= sizeof(*alist));
366         ASSERT(context->firstu <= context->bufsize);
367
368         /*
369          * Only list entries in the right namespace.
370          */
371         if (context->attr_filter != (flags & XFS_ATTR_NSP_ONDISK_MASK))
372                 return;
373
374         arraytop = sizeof(*alist) +
375                         context->count * sizeof(alist->al_offset[0]);
376
377         /* decrement by the actual bytes used by the attr */
378         context->firstu -= round_up(offsetof(struct xfs_attrlist_ent, a_name) +
379                         namelen + 1, sizeof(uint32_t));
380         if (context->firstu < arraytop) {
381                 trace_xfs_attr_list_full(context);
382                 alist->al_more = 1;
383                 context->seen_enough = 1;
384                 return;
385         }
386
387         aep = context->buffer + context->firstu;
388         aep->a_valuelen = valuelen;
389         memcpy(aep->a_name, name, namelen);
390         aep->a_name[namelen] = 0;
391         alist->al_offset[context->count++] = context->firstu;
392         alist->al_count = context->count;
393         trace_xfs_attr_list_add(context);
394 }
395
396 static unsigned int
397 xfs_attr_filter(
398         u32                     ioc_flags)
399 {
400         if (ioc_flags & XFS_IOC_ATTR_ROOT)
401                 return XFS_ATTR_ROOT;
402         if (ioc_flags & XFS_IOC_ATTR_SECURE)
403                 return XFS_ATTR_SECURE;
404         return 0;
405 }
406
407 static inline enum xfs_attr_update
408 xfs_xattr_flags(
409         u32                     ioc_flags,
410         void                    *value)
411 {
412         if (!value)
413                 return XFS_ATTRUPDATE_REMOVE;
414         if (ioc_flags & XFS_IOC_ATTR_CREATE)
415                 return XFS_ATTRUPDATE_CREATE;
416         if (ioc_flags & XFS_IOC_ATTR_REPLACE)
417                 return XFS_ATTRUPDATE_REPLACE;
418         return XFS_ATTRUPDATE_UPSERT;
419 }
420
421 int
422 xfs_ioc_attr_list(
423         struct xfs_inode                *dp,
424         void __user                     *ubuf,
425         size_t                          bufsize,
426         int                             flags,
427         struct xfs_attrlist_cursor __user *ucursor)
428 {
429         struct xfs_attr_list_context    context = { };
430         struct xfs_attrlist             *alist;
431         void                            *buffer;
432         int                             error;
433
434         if (bufsize < sizeof(struct xfs_attrlist) ||
435             bufsize > XFS_XATTR_LIST_MAX)
436                 return -EINVAL;
437
438         /*
439          * Reject flags, only allow namespaces.
440          */
441         if (flags & ~(XFS_IOC_ATTR_ROOT | XFS_IOC_ATTR_SECURE))
442                 return -EINVAL;
443         if (flags == (XFS_IOC_ATTR_ROOT | XFS_IOC_ATTR_SECURE))
444                 return -EINVAL;
445
446         /*
447          * Validate the cursor.
448          */
449         if (copy_from_user(&context.cursor, ucursor, sizeof(context.cursor)))
450                 return -EFAULT;
451         if (context.cursor.pad1 || context.cursor.pad2)
452                 return -EINVAL;
453         if (!context.cursor.initted &&
454             (context.cursor.hashval || context.cursor.blkno ||
455              context.cursor.offset))
456                 return -EINVAL;
457
458         buffer = kvzalloc(bufsize, GFP_KERNEL);
459         if (!buffer)
460                 return -ENOMEM;
461
462         /*
463          * Initialize the output buffer.
464          */
465         context.dp = dp;
466         context.resynch = 1;
467         context.attr_filter = xfs_attr_filter(flags);
468         context.buffer = buffer;
469         context.bufsize = round_down(bufsize, sizeof(uint32_t));
470         context.firstu = context.bufsize;
471         context.put_listent = xfs_ioc_attr_put_listent;
472
473         alist = context.buffer;
474         alist->al_count = 0;
475         alist->al_more = 0;
476         alist->al_offset[0] = context.bufsize;
477
478         error = xfs_attr_list(&context);
479         if (error)
480                 goto out_free;
481
482         if (copy_to_user(ubuf, buffer, bufsize) ||
483             copy_to_user(ucursor, &context.cursor, sizeof(context.cursor)))
484                 error = -EFAULT;
485 out_free:
486         kvfree(buffer);
487         return error;
488 }
489
490 int
491 xfs_attrlist_by_handle(
492         struct file             *parfilp,
493         struct xfs_fsop_attrlist_handlereq __user *p)
494 {
495         struct xfs_fsop_attrlist_handlereq al_hreq;
496         struct dentry           *dentry;
497         int                     error = -ENOMEM;
498
499         if (!capable(CAP_SYS_ADMIN))
500                 return -EPERM;
501         if (copy_from_user(&al_hreq, p, sizeof(al_hreq)))
502                 return -EFAULT;
503
504         dentry = xfs_handlereq_to_dentry(parfilp, &al_hreq.hreq);
505         if (IS_ERR(dentry))
506                 return PTR_ERR(dentry);
507
508         error = xfs_ioc_attr_list(XFS_I(d_inode(dentry)), al_hreq.buffer,
509                                   al_hreq.buflen, al_hreq.flags, &p->pos);
510         dput(dentry);
511         return error;
512 }
513
514 static int
515 xfs_attrmulti_attr_get(
516         struct inode            *inode,
517         unsigned char           *name,
518         unsigned char           __user *ubuf,
519         uint32_t                *len,
520         uint32_t                flags)
521 {
522         struct xfs_da_args      args = {
523                 .dp             = XFS_I(inode),
524                 .attr_filter    = xfs_attr_filter(flags),
525                 .name           = name,
526                 .namelen        = strlen(name),
527                 .valuelen       = *len,
528         };
529         int                     error;
530
531         if (*len > XFS_XATTR_SIZE_MAX)
532                 return -EINVAL;
533
534         error = xfs_attr_get(&args);
535         if (error)
536                 goto out_kfree;
537
538         *len = args.valuelen;
539         if (copy_to_user(ubuf, args.value, args.valuelen))
540                 error = -EFAULT;
541
542 out_kfree:
543         kvfree(args.value);
544         return error;
545 }
546
547 static int
548 xfs_attrmulti_attr_set(
549         struct inode            *inode,
550         unsigned char           *name,
551         const unsigned char     __user *ubuf,
552         uint32_t                len,
553         uint32_t                flags)
554 {
555         struct xfs_da_args      args = {
556                 .dp             = XFS_I(inode),
557                 .attr_filter    = xfs_attr_filter(flags),
558                 .name           = name,
559                 .namelen        = strlen(name),
560         };
561         int                     error;
562
563         if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
564                 return -EPERM;
565
566         if (ubuf) {
567                 if (len > XFS_XATTR_SIZE_MAX)
568                         return -EINVAL;
569                 args.value = memdup_user(ubuf, len);
570                 if (IS_ERR(args.value))
571                         return PTR_ERR(args.value);
572                 args.valuelen = len;
573         }
574
575         error = xfs_attr_change(&args, xfs_xattr_flags(flags, args.value));
576         if (!error && (flags & XFS_IOC_ATTR_ROOT))
577                 xfs_forget_acl(inode, name);
578         kfree(args.value);
579         return error;
580 }
581
582 int
583 xfs_ioc_attrmulti_one(
584         struct file             *parfilp,
585         struct inode            *inode,
586         uint32_t                opcode,
587         void __user             *uname,
588         void __user             *value,
589         uint32_t                *len,
590         uint32_t                flags)
591 {
592         unsigned char           *name;
593         int                     error;
594
595         if ((flags & XFS_IOC_ATTR_ROOT) && (flags & XFS_IOC_ATTR_SECURE))
596                 return -EINVAL;
597
598         name = strndup_user(uname, MAXNAMELEN);
599         if (IS_ERR(name))
600                 return PTR_ERR(name);
601
602         switch (opcode) {
603         case ATTR_OP_GET:
604                 error = xfs_attrmulti_attr_get(inode, name, value, len, flags);
605                 break;
606         case ATTR_OP_REMOVE:
607                 value = NULL;
608                 *len = 0;
609                 fallthrough;
610         case ATTR_OP_SET:
611                 error = mnt_want_write_file(parfilp);
612                 if (error)
613                         break;
614                 error = xfs_attrmulti_attr_set(inode, name, value, *len, flags);
615                 mnt_drop_write_file(parfilp);
616                 break;
617         default:
618                 error = -EINVAL;
619                 break;
620         }
621
622         kfree(name);
623         return error;
624 }
625
626 int
627 xfs_attrmulti_by_handle(
628         struct file             *parfilp,
629         void                    __user *arg)
630 {
631         int                     error;
632         xfs_attr_multiop_t      *ops;
633         xfs_fsop_attrmulti_handlereq_t am_hreq;
634         struct dentry           *dentry;
635         unsigned int            i, size;
636
637         if (!capable(CAP_SYS_ADMIN))
638                 return -EPERM;
639         if (copy_from_user(&am_hreq, arg, sizeof(xfs_fsop_attrmulti_handlereq_t)))
640                 return -EFAULT;
641
642         /* overflow check */
643         if (am_hreq.opcount >= INT_MAX / sizeof(xfs_attr_multiop_t))
644                 return -E2BIG;
645
646         dentry = xfs_handlereq_to_dentry(parfilp, &am_hreq.hreq);
647         if (IS_ERR(dentry))
648                 return PTR_ERR(dentry);
649
650         error = -E2BIG;
651         size = am_hreq.opcount * sizeof(xfs_attr_multiop_t);
652         if (!size || size > 16 * PAGE_SIZE)
653                 goto out_dput;
654
655         ops = memdup_user(am_hreq.ops, size);
656         if (IS_ERR(ops)) {
657                 error = PTR_ERR(ops);
658                 goto out_dput;
659         }
660
661         error = 0;
662         for (i = 0; i < am_hreq.opcount; i++) {
663                 ops[i].am_error = xfs_ioc_attrmulti_one(parfilp,
664                                 d_inode(dentry), ops[i].am_opcode,
665                                 ops[i].am_attrname, ops[i].am_attrvalue,
666                                 &ops[i].am_length, ops[i].am_flags);
667         }
668
669         if (copy_to_user(am_hreq.ops, ops, size))
670                 error = -EFAULT;
671
672         kfree(ops);
673  out_dput:
674         dput(dentry);
675         return error;
676 }
677
678 struct xfs_getparents_ctx {
679         struct xfs_attr_list_context    context;
680         struct xfs_getparents_by_handle gph;
681
682         /* File to target */
683         struct xfs_inode                *ip;
684
685         /* Internal buffer where we format records */
686         void                            *krecords;
687
688         /* Last record filled out */
689         struct xfs_getparents_rec       *lastrec;
690
691         unsigned int                    count;
692 };
693
694 static inline unsigned int
695 xfs_getparents_rec_sizeof(
696         unsigned int            namelen)
697 {
698         return round_up(sizeof(struct xfs_getparents_rec) + namelen + 1,
699                         sizeof(uint64_t));
700 }
701
702 static void
703 xfs_getparents_put_listent(
704         struct xfs_attr_list_context    *context,
705         int                             flags,
706         unsigned char                   *name,
707         int                             namelen,
708         void                            *value,
709         int                             valuelen)
710 {
711         struct xfs_getparents_ctx       *gpx =
712                 container_of(context, struct xfs_getparents_ctx, context);
713         struct xfs_inode                *ip = context->dp;
714         struct xfs_mount                *mp = ip->i_mount;
715         struct xfs_getparents           *gp = &gpx->gph.gph_request;
716         struct xfs_getparents_rec       *gpr = gpx->krecords + context->firstu;
717         unsigned short                  reclen =
718                 xfs_getparents_rec_sizeof(namelen);
719         xfs_ino_t                       ino;
720         uint32_t                        gen;
721         int                             error;
722
723         if (!(flags & XFS_ATTR_PARENT))
724                 return;
725
726         error = xfs_parent_from_attr(mp, flags, name, namelen, value, valuelen,
727                         &ino, &gen);
728         if (error) {
729                 xfs_inode_mark_sick(ip, XFS_SICK_INO_PARENT);
730                 context->seen_enough = -EFSCORRUPTED;
731                 return;
732         }
733
734         /*
735          * We found a parent pointer, but we've filled up the buffer.  Signal
736          * to the caller that we did /not/ reach the end of the parent pointer
737          * recordset.
738          */
739         if (context->firstu > context->bufsize - reclen) {
740                 context->seen_enough = 1;
741                 return;
742         }
743
744         /* Format the parent pointer directly into the caller buffer. */
745         gpr->gpr_reclen = reclen;
746         xfs_filehandle_init(mp, ino, gen, &gpr->gpr_parent);
747         memcpy(gpr->gpr_name, name, namelen);
748         gpr->gpr_name[namelen] = 0;
749
750         trace_xfs_getparents_put_listent(ip, gp, context, gpr);
751
752         context->firstu += reclen;
753         gpx->count++;
754         gpx->lastrec = gpr;
755 }
756
757 /* Expand the last record to fill the rest of the caller's buffer. */
758 static inline void
759 xfs_getparents_expand_lastrec(
760         struct xfs_getparents_ctx       *gpx)
761 {
762         struct xfs_getparents           *gp = &gpx->gph.gph_request;
763         struct xfs_getparents_rec       *gpr = gpx->lastrec;
764
765         if (!gpx->lastrec)
766                 gpr = gpx->krecords;
767
768         gpr->gpr_reclen = gp->gp_bufsize - ((void *)gpr - gpx->krecords);
769
770         trace_xfs_getparents_expand_lastrec(gpx->ip, gp, &gpx->context, gpr);
771 }
772
773 /* Retrieve the parent pointers for a given inode. */
774 STATIC int
775 xfs_getparents(
776         struct xfs_getparents_ctx       *gpx)
777 {
778         struct xfs_getparents           *gp = &gpx->gph.gph_request;
779         struct xfs_inode                *ip = gpx->ip;
780         struct xfs_mount                *mp = ip->i_mount;
781         size_t                          bufsize;
782         int                             error;
783
784         /* Check size of buffer requested by user */
785         if (gp->gp_bufsize > XFS_XATTR_LIST_MAX)
786                 return -ENOMEM;
787         if (gp->gp_bufsize < xfs_getparents_rec_sizeof(1))
788                 return -EINVAL;
789
790         if (gp->gp_iflags & ~XFS_GETPARENTS_IFLAGS_ALL)
791                 return -EINVAL;
792         if (gp->gp_reserved)
793                 return -EINVAL;
794
795         bufsize = round_down(gp->gp_bufsize, sizeof(uint64_t));
796         gpx->krecords = kvzalloc(bufsize, GFP_KERNEL);
797         if (!gpx->krecords) {
798                 bufsize = min(bufsize, PAGE_SIZE);
799                 gpx->krecords = kvzalloc(bufsize, GFP_KERNEL);
800                 if (!gpx->krecords)
801                         return -ENOMEM;
802         }
803
804         gpx->context.dp = ip;
805         gpx->context.resynch = 1;
806         gpx->context.put_listent = xfs_getparents_put_listent;
807         gpx->context.bufsize = bufsize;
808         /* firstu is used to track the bytes filled in the buffer */
809         gpx->context.firstu = 0;
810
811         /* Copy the cursor provided by caller */
812         memcpy(&gpx->context.cursor, &gp->gp_cursor,
813                         sizeof(struct xfs_attrlist_cursor));
814         gpx->count = 0;
815         gp->gp_oflags = 0;
816
817         trace_xfs_getparents_begin(ip, gp, &gpx->context.cursor);
818
819         error = xfs_attr_list(&gpx->context);
820         if (error)
821                 goto out_free_buf;
822         if (gpx->context.seen_enough < 0) {
823                 error = gpx->context.seen_enough;
824                 goto out_free_buf;
825         }
826         xfs_getparents_expand_lastrec(gpx);
827
828         /* Update the caller with the current cursor position */
829         memcpy(&gp->gp_cursor, &gpx->context.cursor,
830                         sizeof(struct xfs_attrlist_cursor));
831
832         /* Is this the root directory? */
833         if (ip->i_ino == mp->m_sb.sb_rootino)
834                 gp->gp_oflags |= XFS_GETPARENTS_OFLAG_ROOT;
835
836         if (gpx->context.seen_enough == 0) {
837                 /*
838                  * If we did not run out of buffer space, then we reached the
839                  * end of the pptr recordset, so set the DONE flag.
840                  */
841                 gp->gp_oflags |= XFS_GETPARENTS_OFLAG_DONE;
842         } else if (gpx->count == 0) {
843                 /*
844                  * If we ran out of buffer space before copying any parent
845                  * pointers at all, the caller's buffer was too short.  Tell
846                  * userspace that, erm, the message is too long.
847                  */
848                 error = -EMSGSIZE;
849                 goto out_free_buf;
850         }
851
852         trace_xfs_getparents_end(ip, gp, &gpx->context.cursor);
853
854         ASSERT(gpx->context.firstu <= gpx->gph.gph_request.gp_bufsize);
855
856         /* Copy the records to userspace. */
857         if (copy_to_user(u64_to_user_ptr(gpx->gph.gph_request.gp_buffer),
858                                 gpx->krecords, gpx->context.firstu))
859                 error = -EFAULT;
860
861 out_free_buf:
862         kvfree(gpx->krecords);
863         gpx->krecords = NULL;
864         return error;
865 }
866
867 /* Retrieve the parents of this file and pass them back to userspace. */
868 int
869 xfs_ioc_getparents(
870         struct file                     *file,
871         struct xfs_getparents __user    *ureq)
872 {
873         struct xfs_getparents_ctx       gpx = {
874                 .ip                     = XFS_I(file_inode(file)),
875         };
876         struct xfs_getparents           *kreq = &gpx.gph.gph_request;
877         struct xfs_mount                *mp = gpx.ip->i_mount;
878         int                             error;
879
880         if (!capable(CAP_SYS_ADMIN))
881                 return -EPERM;
882         if (!xfs_has_parent(mp))
883                 return -EOPNOTSUPP;
884         if (copy_from_user(kreq, ureq, sizeof(*kreq)))
885                 return -EFAULT;
886
887         error = xfs_getparents(&gpx);
888         if (error)
889                 return error;
890
891         if (copy_to_user(ureq, kreq, sizeof(*kreq)))
892                 return -EFAULT;
893
894         return 0;
895 }
896
897 /* Retrieve the parents of this file handle and pass them back to userspace. */
898 int
899 xfs_ioc_getparents_by_handle(
900         struct file                     *file,
901         struct xfs_getparents_by_handle __user  *ureq)
902 {
903         struct xfs_getparents_ctx       gpx = { };
904         struct xfs_inode                *ip = XFS_I(file_inode(file));
905         struct xfs_mount                *mp = ip->i_mount;
906         struct xfs_getparents_by_handle *kreq = &gpx.gph;
907         struct xfs_handle               *handle = &kreq->gph_handle;
908         int                             error;
909
910         if (!capable(CAP_SYS_ADMIN))
911                 return -EPERM;
912         if (!xfs_has_parent(mp))
913                 return -EOPNOTSUPP;
914         if (copy_from_user(kreq, ureq, sizeof(*kreq)))
915                 return -EFAULT;
916
917         /*
918          * We don't use exportfs_decode_fh because it does too much work here.
919          * If the handle refers to a directory, the exportfs code will walk
920          * upwards through the directory tree to connect the dentries to the
921          * root directory dentry.  For GETPARENTS we don't care about that
922          * because we're not actually going to open a file descriptor; we only
923          * want to open an inode and read its parent pointers.
924          *
925          * Note that xfs_scrub uses GETPARENTS to log that it will try to fix a
926          * corrupted file's metadata.  For this usecase we would really rather
927          * userspace single-step the path reconstruction to avoid loops or
928          * other strange things if the directory tree is corrupt.
929          */
930         gpx.ip = xfs_khandle_to_inode(file, handle);
931         if (IS_ERR(gpx.ip))
932                 return PTR_ERR(gpx.ip);
933
934         error = xfs_getparents(&gpx);
935         if (error)
936                 goto out_rele;
937
938         if (copy_to_user(ureq, kreq, sizeof(*kreq)))
939                 error = -EFAULT;
940
941 out_rele:
942         xfs_irele(gpx.ip);
943         return error;
944 }
This page took 0.079405 seconds and 4 git commands to generate.