Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.9.4.
  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			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
310int
311xfs_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 */
349static void
350xfs_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
396static unsigned int
397xfs_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
407static inline enum xfs_attr_update
408xfs_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
421int
422xfs_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;
485out_free:
486	kvfree(buffer);
487	return error;
488}
489
490int
491xfs_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
514static int
515xfs_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
542out_kfree:
543	kvfree(args.value);
544	return error;
545}
546
547static int
548xfs_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
582int
583xfs_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
626int
627xfs_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
678struct 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
694static inline unsigned int
695xfs_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
702static void
703xfs_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. */
758static inline void
759xfs_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. */
774STATIC int
775xfs_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
861out_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. */
868int
869xfs_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. */
898int
899xfs_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
941out_rele:
942	xfs_irele(gpx.ip);
943	return error;
944}