All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Darrick J. Wong" <darrick.wong@oracle.com>
To: Allison Henderson <allison.henderson@oracle.com>
Cc: xfs <linux-xfs@vger.kernel.org>
Subject: [RFCRAP DONOTMERGE PATCH 1/2] xfs: sketchy implementation of parent pointers
Date: Thu, 7 Dec 2017 20:02:22 -0800	[thread overview]
Message-ID: <20171208040222.GE19219@magnolia> (raw)
In-Reply-To: <20171208035457.GD19219@magnolia>

From: Darrick J. Wong <darrick.wong@oracle.com>

This is a, um, "sample" implementation of parent pointers that abuses
struct dentry to return one parent pointer of a file ... if the dentry
cache has been connected.  This exists only to enable testing of the
userspace xfs_scrub bits and is probably too ugly to live.  Wait for the
real implementation.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/Makefile        |    1 
 fs/xfs/libxfs/xfs_fs.h |   57 +++++++++++++
 fs/xfs/xfs_ioctl.c     |   49 +++++++++++
 fs/xfs/xfs_parent.c    |  214 ++++++++++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_parent.h    |   29 +++++++
 5 files changed, 350 insertions(+)
 create mode 100644 fs/xfs/xfs_parent.c
 create mode 100644 fs/xfs/xfs_parent.h

diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index e1768e7..9f4de14 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -99,6 +99,7 @@ xfs-y				+= xfs_aops.o \
 				   xfs_message.o \
 				   xfs_mount.o \
 				   xfs_mru_cache.o \
+				   xfs_parent.o \
 				   xfs_reflink.o \
 				   xfs_stats.o \
 				   xfs_super.o \
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index fc4386a..f0ff964 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -545,6 +545,62 @@ struct xfs_scrub_metadata {
 				 XFS_SCRUB_OFLAG_WARNING)
 #define XFS_SCRUB_FLAGS_ALL	(XFS_SCRUB_FLAGS_IN | XFS_SCRUB_FLAGS_OUT)
 
+/* Parent Pointers */
+#define XFS_PPTR_NAME_MAX	256
+
+struct xfs_pptr {
+	/* Parent inode number. */
+	__u64				pp_ino;
+	__u64				pp_reserved[2];
+
+	/* Parent generation number. */
+	__u32				pp_gen;
+
+	/* Name in the parent. */
+	__u32				pp_namelen;
+	__u8				pp_name[XFS_PPTR_NAME_MAX];
+};
+
+/* return parents of the handle, not the open fd */
+#define XFS_PPTR_IFLAG_HANDLE	(1U << 0)
+
+#define XFS_PPTR_ALL_IFLAGS	(XFS_PPTR_IFLAG_HANDLE)
+
+/* partial results only */
+#define XFS_PPTR_OFLAG_PARTIAL	(1U << 0)
+
+/* target was the root directory */
+#define XFS_PPTR_OFLAG_ROOT	(1U << 1)
+
+struct xfs_pptr_info {
+	/* i: (optional) file handle. */
+	struct xfs_handle		pi_handle;
+
+	/* i/o: xattr lookup cursor, if necessary */
+	struct xfs_attrlist_cursor	pi_cursor;
+
+	/* i: input flags */
+	__u32				pi_iflags;
+
+	/* o: output flags */
+	__u32				pi_oflags;
+
+	/* i: number of pointers we have space for. */
+	__u32				pi_ptrs_size;
+
+	/* o: number of pointers actually returned. */
+	__u32				pi_ptrs_used;
+
+	/* must be zero */
+	__u64				pi_reserved[6];
+
+	/* o: pointer info, must come last */
+	struct xfs_pptr			pi_ptrs[0];
+};
+
+#define XFS_PPTR_INFO_SIZEOF(nr_ptrs)	(sizeof(struct xfs_pptr_info) + \
+					((nr_ptrs) * sizeof(struct xfs_pptr)))
+
 /*
  * ioctl limits
  */
@@ -589,6 +645,7 @@ struct xfs_scrub_metadata {
 #define XFS_IOC_FREE_EOFBLOCKS	_IOR ('X', 58, struct xfs_fs_eofblocks)
 /*	XFS_IOC_GETFSMAP ------ hoisted 59         */
 #define XFS_IOC_SCRUB_METADATA	_IOWR('X', 60, struct xfs_scrub_metadata)
+#define XFS_IOC_GET_PPTR	_IOWR('X', 61, struct xfs_pptr_info)
 
 /*
  * ioctl commands that replace IRIX syssgi()'s
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 20dc65f..916b060 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -45,6 +45,7 @@
 #include <linux/fsmap.h>
 #include "xfs_fsmap.h"
 #include "scrub/xfs_scrub.h"
+#include "xfs_parent.h"
 
 #include <linux/capability.h>
 #include <linux/cred.h>
@@ -1730,6 +1731,51 @@ xfs_ioc_scrub_metadata(
 	return 0;
 }
 
+struct getpptr_info {
+	struct xfs_pptr_info __user *data;
+	unsigned int		idx;
+};
+
+STATIC int
+xfs_getpptr_format(
+	struct xfs_pptr		*pp,
+	void			*arg)
+{
+	struct getpptr_info	*info = arg;
+
+	if (copy_to_user(&info->data->pi_ptrs[info->idx++], pp,
+			sizeof(struct xfs_pptr)))
+		return -EFAULT;
+	return 0;
+}
+
+STATIC int
+xfs_ioc_get_parent_pointers(
+	struct file		*filp,
+	void			__user *arg)
+{
+	struct getpptr_info	info = { NULL };
+	struct xfs_pptr_info	pi;
+	int			error;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (copy_from_user(&pi, arg, sizeof(pi)))
+		return -EFAULT;
+
+	info.data = arg;
+	error = xfs_parent_get_pointers(filp, &pi, xfs_getpptr_format, &info);
+	if (error)
+		return error;
+
+	pi.pi_ptrs_used = info.idx;
+	if (copy_to_user(arg, &pi, sizeof(pi)))
+		return -EFAULT;
+
+	return 0;
+}
+
 int
 xfs_ioc_swapext(
 	xfs_swapext_t	*sxp)
@@ -1914,6 +1960,9 @@ xfs_file_ioctl(
 	case XFS_IOC_SCRUB_METADATA:
 		return xfs_ioc_scrub_metadata(ip, arg);
 
+	case XFS_IOC_GET_PPTR:
+		return xfs_ioc_get_parent_pointers(filp, arg);
+
 	case XFS_IOC_FD_TO_HANDLE:
 	case XFS_IOC_PATH_TO_HANDLE:
 	case XFS_IOC_PATH_TO_FSHANDLE: {
diff --git a/fs/xfs/xfs_parent.c b/fs/xfs/xfs_parent.c
new file mode 100644
index 0000000..91b07e0
--- /dev/null
+++ b/fs/xfs/xfs_parent.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2017 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_mount.h"
+#include "xfs_btree.h"
+#include "xfs_bit.h"
+#include "xfs_log_format.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_inode.h"
+#include "xfs_icache.h"
+#include "xfs_itable.h"
+#include "xfs_export.h"
+#include "xfs_parent.h"
+
+struct xfs_pptr_buf {
+	uint32_t		idx;
+	struct xfs_pptr		recs[0];
+};
+
+#define XFS_PARENT_ITER_ABORT	(1)
+
+/* Package up a pptr structure and emit it to the caller. */
+static int
+xfs_parent_emit(
+	struct xfs_pptr_info	*pi,
+	struct xfs_pptr_buf	*pb,
+	uint64_t		ino,
+	uint32_t		gen,
+	uint8_t			namelen,
+	const char		*name)
+{
+	struct xfs_pptr		*pptr;
+
+	if (pb->idx >= pi->pi_ptrs_size)
+		return XFS_PARENT_ITER_ABORT;
+
+	pptr = &pb->recs[pb->idx++];
+	pptr->pp_ino = ino;
+	pptr->pp_gen = gen;
+	pptr->pp_namelen = namelen;
+	memcpy(pptr->pp_name, name, namelen);
+
+	return 0;
+}
+
+/*
+ * No need to do permission checks on the various pathname components
+ * as the handle operations are privileged.
+ */
+STATIC int
+xfs_parent_handle_acceptable(
+	void			*context,
+	struct dentry		*dentry)
+{
+	return 1;
+}
+
+/* Get parent info for an inode by walking the parent dentry. */
+static int
+xfs_parent_get_dparent(
+	struct file		*filp,
+	struct xfs_pptr_info	*pi,
+	struct xfs_pptr_buf	*pb)
+{
+	struct xfs_inode	*ip;
+	struct inode		*dir_inode;
+	struct dentry		*dentry;
+	struct dentry		*dparent;
+	unsigned int		ilock;
+	int			error = 0;
+
+	pi->pi_oflags |= XFS_PPTR_OFLAG_PARTIAL;
+
+	/* Any nonzero byte in the cursor means we've already retrieved one. */
+	if (memchr_inv(&pi->pi_cursor, 0, sizeof(pi->pi_cursor)))
+		return 0;
+	memset(&pi->pi_cursor, 0xFF, sizeof(pi->pi_cursor));
+
+	if (pi->pi_iflags & XFS_PPTR_IFLAG_HANDLE) {
+		struct xfs_handle	*handle = &pi->pi_handle;
+		struct xfs_fid64	fid = { 0 };
+
+		/* Extract the desired file from the handle info. */
+		if (sizeof(handle->ha_fid) - sizeof(handle->ha_fid.fid_len) !=
+				handle->ha_fid.fid_len)
+			return -EINVAL;
+
+		fid.ino = handle->ha_fid.fid_ino;
+		fid.gen = handle->ha_fid.fid_gen;
+
+		dentry = exportfs_decode_fh(filp->f_path.mnt,
+				(struct fid *)&fid, 3,
+				FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG,
+				xfs_parent_handle_acceptable, NULL);
+		if (IS_ERR(dentry))
+			return PTR_ERR(dentry);
+	} else {
+		/* Or just use the dentry of the open file. */
+		dentry = dget(file_dentry(filp));
+	}
+
+	/* Lock XFS inode... */
+	ip = XFS_I(d_inode(dentry));
+	ilock = XFS_IOLOCK_SHARED | XFS_MMAPLOCK_SHARED | XFS_ILOCK_SHARED;
+	xfs_ilock(ip, ilock);
+
+	/* Bail out early for the root dir. */
+	if (ip->i_ino == ip->i_mount->m_sb.sb_rootino) {
+		pi->pi_oflags |= XFS_PPTR_OFLAG_ROOT;
+		goto out_dentry;
+	}
+
+	/* Filter out the unconnected inodes. */
+	if (d_unlinked(dentry) || (dentry->d_flags & DCACHE_DISCONNECTED))
+		goto out_dentry;
+	if (IS_ROOT(dentry)) {
+		pi->pi_oflags |= XFS_PPTR_OFLAG_ROOT;
+		goto out_dentry;
+	}
+
+	/* Otherwise look up the parent... */
+	dparent = dget_parent(dentry);
+	if (IS_ERR(dparent)) {
+		error = PTR_ERR(dparent);
+		goto out_dentry;
+	}
+
+	dir_inode = d_inode(dparent);
+	if (!dir_inode)
+		goto out_dparent;
+
+	/* ...and emit a record. */
+	error = xfs_parent_emit(pi, pb, dir_inode->i_ino,
+			dir_inode->i_generation,
+			ACCESS_ONCE(dentry->d_name.len),
+			ACCESS_ONCE(dentry->d_name.name));
+	if (error == XFS_PARENT_ITER_ABORT)
+		error = 0;
+
+out_dparent:
+	dput(dparent);
+out_dentry:
+	xfs_iunlock(ip, ilock);
+	dput(dentry);
+	return error;
+}
+
+/* Walk all the parent pointers of a file. */
+int
+xfs_parent_get_pointers(
+	struct file		*filp,
+	struct xfs_pptr_info	*pi,
+	xfs_parent_format_t	formatter,
+	void			*arg)
+{
+	struct xfs_pptr_buf	*pb;
+	size_t			sz;
+	unsigned int		i;
+	int			error;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (pi->pi_iflags & ~XFS_PPTR_ALL_IFLAGS)
+		return -EINVAL;
+	if (memchr_inv(pi->pi_reserved, 0, sizeof(pi->pi_reserved)))
+		return -EINVAL;
+
+	/*
+	 * Allocate temporary buffer to hold pptr records while we have
+	 * the inode locked.
+	 */
+	sz = sizeof(struct xfs_pptr_buf) +
+			(pi->pi_ptrs_size * sizeof(struct xfs_pptr));
+	if (sz > PAGE_SIZE * 4)
+		return -ENOMEM;
+	pb = kmem_zalloc_large(sz, KM_SLEEP | KM_MAYFAIL);
+	if (!pb)
+		return -ENOMEM;
+
+	/* Record parent pointer information in buffer. */
+	error = xfs_parent_get_dparent(filp, pi, pb);
+	if (error)
+		goto out;
+
+	/* Format records to userspace. */
+	for (i = 0; error == 0 && i < pb->idx; i++)
+		error = formatter(&pb->recs[i], arg);
+
+out:
+	kmem_free(pb);
+	return error;
+}
diff --git a/fs/xfs/xfs_parent.h b/fs/xfs/xfs_parent.h
new file mode 100644
index 0000000..23ee505
--- /dev/null
+++ b/fs/xfs/xfs_parent.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+#ifndef __XFS_PARENT_H__
+#define __XFS_PARENT_H__
+
+/* pptr to userspace formatter - copy to user & advance pointer */
+typedef int (*xfs_parent_format_t)(struct xfs_pptr *, void *);
+
+int xfs_parent_get_pointers(struct file *filp, struct xfs_pptr_info *pi,
+		xfs_parent_format_t formatter, void *priv);
+
+#endif /* __XFS_PARENT_H__ */

  reply	other threads:[~2017-12-08  4:02 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-12-08  3:54 [RFCRAP DONOTMERGE PATCH 0/2] xfs: parent pointers Darrick J. Wong
2017-12-08  4:02 ` Darrick J. Wong [this message]
2017-12-08  7:52   ` [RFCRAP DONOTMERGE PATCH 1/2] xfs: sketchy implementation of " Amir Goldstein
2017-12-08  4:03 ` [RFCRAP DONOTMERGE PATCH 2/2] xfsprogs: implement the upper half " Darrick J. Wong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20171208040222.GE19219@magnolia \
    --to=darrick.wong@oracle.com \
    --cc=allison.henderson@oracle.com \
    --cc=linux-xfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.