File Index
Files and directories
Sign in
FILE

xfs_handle.c

File preview with syntax highlighting.

linux-6.19.14/fs/xfs/xfs_handle.c 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
 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}
~/ Read-only file preview.