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