@@ -796,6 +796,7 @@ struct xfs_scrub_metadata {
/* 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)
+/* XFS_IOC_GETPARENTS ---- staging 62 */
/*
* ioctl commands that replace IRIX syssgi()'s
@@ -15,4 +15,70 @@
* explaining where it went.
*/
+/* Iterating parent pointers of files. */
+
+/* return parents of the handle, not the open fd */
+#define XFS_GETPARENTS_IFLAG_HANDLE (1U << 0)
+
+/* target was the root directory */
+#define XFS_GETPARENTS_OFLAG_ROOT (1U << 1)
+
+/* Cursor is done iterating pptrs */
+#define XFS_GETPARENTS_OFLAG_DONE (1U << 2)
+
+#define XFS_GETPARENTS_FLAG_ALL (XFS_GETPARENTS_IFLAG_HANDLE | \
+ XFS_GETPARENTS_OFLAG_ROOT | \
+ XFS_GETPARENTS_OFLAG_DONE)
+
+/* Get an inode parent pointer through ioctl */
+struct xfs_getparents_rec {
+ __u64 gpr_ino; /* Inode number */
+ __u32 gpr_gen; /* Inode generation */
+ __u32 gpr_pad; /* Reserved */
+ __u64 gpr_rsvd; /* Reserved */
+ __u8 gpr_name[]; /* File name and null terminator */
+};
+
+/* Iterate through an inodes parent pointers */
+struct xfs_getparents {
+ /* File handle, if XFS_GETPARENTS_IFLAG_HANDLE is set */
+ struct xfs_handle gp_handle;
+
+ /*
+ * 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;
+
+ /* Operational flags: XFS_GETPARENTS_*FLAG* */
+ __u32 gp_flags;
+
+ /* Must be set to zero */
+ __u32 gp_reserved;
+
+ /* Size of the buffer in bytes, including this header */
+ __u32 gp_bufsize;
+
+ /* # of entries filled in (output) */
+ __u32 gp_count;
+
+ /* Must be set to zero */
+ __u64 gp_reserved2[5];
+
+ /* Byte offset of each record within the buffer */
+ __u32 gp_offsets[];
+};
+
+static inline struct xfs_getparents_rec*
+xfs_getparents_rec(
+ struct xfs_getparents *info,
+ unsigned int idx)
+{
+ return (struct xfs_getparents_rec *)((char *)info +
+ info->gp_offsets[idx]);
+}
+
+#define XFS_IOC_GETPARENTS _IOWR('X', 62, struct xfs_getparents)
+
#endif /* __XFS_FS_STAGING_H__ */
@@ -276,3 +276,43 @@ xfs_parent_calc_space_res(
return XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) +
XFS_NEXTENTADD_SPACE_RES(mp, namelen, XFS_ATTR_FORK);
}
+
+/* Convert an ondisk parent pointer to the incore format. */
+void
+xfs_parent_irec_from_disk(
+ struct xfs_parent_name_irec *irec,
+ const struct xfs_parent_name_rec *rec,
+ const void *value,
+ unsigned int valuelen)
+{
+ irec->p_ino = be64_to_cpu(rec->p_ino);
+ irec->p_gen = be32_to_cpu(rec->p_gen);
+ irec->p_namehash = be32_to_cpu(rec->p_namehash);
+ irec->p_namelen = valuelen;
+ memcpy(irec->p_name, value, valuelen);
+}
+
+/* Convert an incore parent pointer to the ondisk attr name format. */
+void
+xfs_parent_irec_to_disk(
+ struct xfs_parent_name_rec *rec,
+ const struct xfs_parent_name_irec *irec)
+{
+ rec->p_ino = cpu_to_be64(irec->p_ino);
+ rec->p_gen = cpu_to_be32(irec->p_gen);
+ rec->p_namehash = cpu_to_be32(irec->p_namehash);
+}
+
+/* Compute p_namehash for the this parent pointer. */
+void
+xfs_parent_irec_hashname(
+ struct xfs_mount *mp,
+ struct xfs_parent_name_irec *irec)
+{
+ struct xfs_name dname = {
+ .name = irec->p_name,
+ .len = irec->p_namelen,
+ };
+
+ irec->p_namehash = xfs_dir2_hashname(mp, &dname);
+}
@@ -78,4 +78,27 @@ xfs_parent_finish(
unsigned int xfs_parent_calc_space_res(struct xfs_mount *mp,
unsigned int namelen);
+/*
+ * Incore version of a parent pointer, also contains dirent name so callers
+ * can pass/obtain all the parent pointer information in a single structure
+ */
+struct xfs_parent_name_irec {
+ /* Parent pointer attribute name fields */
+ xfs_ino_t p_ino;
+ uint32_t p_gen;
+ xfs_dahash_t p_namehash;
+
+ /* Parent pointer attribute value fields */
+ uint8_t p_namelen;
+ unsigned char p_name[MAXNAMELEN];
+};
+
+void xfs_parent_irec_from_disk(struct xfs_parent_name_irec *irec,
+ const struct xfs_parent_name_rec *rec, const void *value,
+ unsigned int valuelen);
+void xfs_parent_irec_to_disk(struct xfs_parent_name_rec *rec,
+ const struct xfs_parent_name_irec *irec);
+void xfs_parent_irec_hashname(struct xfs_mount *mp,
+ struct xfs_parent_name_irec *irec);
+
#endif /* __XFS_PARENT_H__ */
@@ -321,6 +321,69 @@ They are all subject to change and should not be called directly
by applications.
XFS_IOC_FSSETDM_BY_HANDLE is not supported as of Linux 5.5.
+.PP
+.TP
+.B XFS_IOC_GETPARENTS
+This command is used to get a file's parent pointers.
+Parent pointers point upwards in the directory tree towards directories that
+have entries pointing downwards.
+
+Calling programs should allocate a large memory buffer, initialize the head
+structure to zeroes, set gp_bufsize to the size of the buffer, and call the
+ioctl.
+The kernel will fill out the gp_offsets array with integer offsets to
+struct xfs_getparents_rec objects that are written within the provided memory
+buffer.
+The size of the gp_offsets array is given by gp_count.
+The XFS_GETPARENTS_OFLAG_DONE flag will be set in gp_flags when there are no
+more parent pointers to be read.
+The below code is an example of XFS_IOC_GETPARENTS usage:
+
+.nf
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <xfs/linux.h>
+#include <xfs/xfs.h>
+#include <xfs/xfs_types.h>
+#include <xfs/xfs_fs.h>
+#include <xfs/xfs_fs_staging.h>
+
+int main() {
+ struct xfs_getparents *pi;
+ struct xfs_getparents_rec *p;
+ int i, error, fd, nr_ptrs = 4;
+
+ error = malloc(65536);
+ if (!error) {
+ perror("malloc");
+ return 1;
+ }
+
+ memset(pi, 0, sizeof(*pi));
+ pi->gp_bufsize = 65536;
+
+ fd = open("/mnt/test/foo.txt", O_RDONLY | O_CREAT);
+ if (fd == -1)
+ return errno;
+
+ do {
+ error = ioctl(fd, XFS_IOC_GETPARENTS, pi);
+ if (error)
+ return error;
+
+ for (i = 0; i < pi->gp_count; i++) {
+ p = xfs_getparents_rec(pi, i);
+ printf("inode = %llu\\n", (unsigned long long)p->gpr_ino);
+ printf("generation = %u\\n", (unsigned int)p->gpr_gen);
+ printf("name = \\"%s\\"\\n\\n", (char *)p->gpr_name);
+ }
+ } while (!(pi->gp_flags & XFS_GETPARENTS_OFLAG_DONE));
+
+ return 0;
+}
+.fi
+
.SS Filesystem Operations
In order to effect one of the following operations, the pathname
and descriptor arguments passed to