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