Commit 233f4e12 authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

xfs: add parent pointer ioctls



This patch adds a pair of new file ioctls to retrieve the parent pointer
of a given inode.  They both return the same results, but one operates
on the file descriptor passed to ioctl() whereas the other allows the
caller to specify a file handle for which the caller wants results.

Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent b8c9d425
Loading
Loading
Loading
Loading
+74 −0
Original line number Diff line number Diff line
@@ -816,6 +816,78 @@ struct xfs_exchange_range {
					 XFS_EXCHANGE_RANGE_DRY_RUN | \
					 XFS_EXCHANGE_RANGE_FILE1_WRITTEN)

/* Iterating parent pointers of files. */

/* target was the root directory */
#define XFS_GETPARENTS_OFLAG_ROOT	(1U << 0)

/* Cursor is done iterating pptrs */
#define XFS_GETPARENTS_OFLAG_DONE	(1U << 1)

#define XFS_GETPARENTS_OFLAGS_ALL	(XFS_GETPARENTS_OFLAG_ROOT | \
					 XFS_GETPARENTS_OFLAG_DONE)

#define XFS_GETPARENTS_IFLAGS_ALL	(0)

struct xfs_getparents_rec {
	struct xfs_handle	gpr_parent; /* Handle to parent */
	__u32			gpr_reclen; /* Length of entire record */
	__u32			gpr_reserved; /* zero */
	char			gpr_name[]; /* Null-terminated filename */
};

/* Iterate through this file's directory parent pointers */
struct xfs_getparents {
	/*
	 * Structure to track progress in iterating the parent pointers.
	 * Must be initialized to zeroes before the first ioctl call, and
	 * not touched by callers after that.
	 */
	struct xfs_attrlist_cursor	gp_cursor;

	/* Input flags: XFS_GETPARENTS_IFLAG* */
	__u16				gp_iflags;

	/* Output flags: XFS_GETPARENTS_OFLAG* */
	__u16				gp_oflags;

	/* Size of the gp_buffer in bytes */
	__u32				gp_bufsize;

	/* Must be set to zero */
	__u64				gp_reserved;

	/* Pointer to a buffer in which to place xfs_getparents_rec */
	__u64				gp_buffer;
};

static inline struct xfs_getparents_rec *
xfs_getparents_first_rec(struct xfs_getparents *gp)
{
	return (struct xfs_getparents_rec *)(uintptr_t)gp->gp_buffer;
}

static inline struct xfs_getparents_rec *
xfs_getparents_next_rec(struct xfs_getparents *gp,
			struct xfs_getparents_rec *gpr)
{
	void *next = ((void *)gpr + gpr->gpr_reclen);
	void *end = (void *)(uintptr_t)(gp->gp_buffer + gp->gp_bufsize);

	if (next >= end)
		return NULL;

	return next;
}

/* Iterate through this file handle's directory parent pointers. */
struct xfs_getparents_by_handle {
	/* Handle to file whose parents we want. */
	struct xfs_handle		gph_handle;

	struct xfs_getparents		gph_request;
};

/*
 * ioctl commands that are used by Linux filesystems
 */
@@ -851,6 +923,8 @@ struct xfs_exchange_range {
/*	XFS_IOC_GETFSMAP ------ hoisted 59         */
#define XFS_IOC_SCRUB_METADATA	_IOWR('X', 60, struct xfs_scrub_metadata)
#define XFS_IOC_AG_GEOMETRY	_IOWR('X', 61, struct xfs_ag_geometry)
#define XFS_IOC_GETPARENTS	_IOWR('X', 62, struct xfs_getparents)
#define XFS_IOC_GETPARENTS_BY_HANDLE _IOWR('X', 63, struct xfs_getparents_by_handle)

/*
 * ioctl commands that replace IRIX syssgi()'s
+5 −0
Original line number Diff line number Diff line
@@ -156,6 +156,11 @@ xfs_check_ondisk_structs(void)
	XFS_CHECK_OFFSET(struct xfs_efi_log_format_32, efi_extents,	16);
	XFS_CHECK_OFFSET(struct xfs_efi_log_format_64, efi_extents,	16);

	/* parent pointer ioctls */
	XFS_CHECK_STRUCT_SIZE(struct xfs_getparents_rec,	32);
	XFS_CHECK_STRUCT_SIZE(struct xfs_getparents,		40);
	XFS_CHECK_STRUCT_SIZE(struct xfs_getparents_by_handle,	64);

	/*
	 * The v5 superblock format extended several v4 header structures with
	 * additional data. While new fields are only accessible on v5
+34 −0
Original line number Diff line number Diff line
@@ -257,3 +257,37 @@ xfs_parent_replacename(
	xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_REPLACE);
	return 0;
}

/*
 * Extract parent pointer information from any parent pointer xattr into
 * @parent_ino/gen.  The last two parameters can be NULL pointers.
 *
 * Returns 0 if this is not a parent pointer xattr at all; or -EFSCORRUPTED for
 * garbage.
 */
int
xfs_parent_from_attr(
	struct xfs_mount	*mp,
	unsigned int		attr_flags,
	const unsigned char	*name,
	unsigned int		namelen,
	const void		*value,
	unsigned int		valuelen,
	xfs_ino_t		*parent_ino,
	uint32_t		*parent_gen)
{
	const struct xfs_parent_rec	*rec = value;

	ASSERT(attr_flags & XFS_ATTR_PARENT);

	if (!xfs_parent_namecheck(attr_flags, name, namelen))
		return -EFSCORRUPTED;
	if (!xfs_parent_valuecheck(mp, value, valuelen))
		return -EFSCORRUPTED;

	if (parent_ino)
		*parent_ino = be64_to_cpu(rec->p_ino);
	if (parent_gen)
		*parent_gen = be32_to_cpu(rec->p_gen);
	return 0;
}
+5 −0
Original line number Diff line number Diff line
@@ -91,4 +91,9 @@ int xfs_parent_replacename(struct xfs_trans *tp,
		struct xfs_inode *new_dp, const struct xfs_name *new_name,
		struct xfs_inode *child);

int xfs_parent_from_attr(struct xfs_mount *mp, unsigned int attr_flags,
		const unsigned char *name, unsigned int namelen,
		const void *value, unsigned int valuelen,
		xfs_ino_t *parent_ino, uint32_t *parent_gen);

#endif /* __XFS_PARENT_H__ */
+1 −1
Original line number Diff line number Diff line
@@ -102,7 +102,7 @@ xfs_fs_encode_fh(
	return fileid_type;
}

STATIC struct inode *
struct inode *
xfs_nfs_get_inode(
	struct super_block	*sb,
	u64			ino,
Loading