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__ */
next prev parent 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.