]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs: add parent pointer validator functions
authorAllison Henderson <allison.henderson@oracle.com>
Tue, 9 Jan 2024 17:41:35 +0000 (09:41 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 10 Apr 2024 00:21:29 +0000 (17:21 -0700)
Attribute names of parent pointers are not strings.  So we need to
modify attr_namecheck to verify parent pointer records when the
XFS_ATTR_PARENT flag is set.  At the same time, we need to validate attr
values during log recovery if the xattr is really a parent pointer.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
[djwong: move functions to xfs_parent.c, adjust for new disk format]
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
libxfs/Makefile
libxfs/xfs_attr.c
libxfs/xfs_parent.c [new file with mode: 0644]
libxfs/xfs_parent.h [new file with mode: 0644]

index e3fa18feeaa3da7d97628b76dc49fe02fb4f94ab..2a5cead9aa19432ed647583335f2cbf75312bb75 100644 (file)
@@ -50,6 +50,7 @@ HFILES = \
        xfs_ialloc_btree.h \
        xfs_inode_buf.h \
        xfs_inode_fork.h \
+       xfs_parent.h \
        xfs_quota_defs.h \
        xfs_refcount.h \
        xfs_refcount_btree.h \
@@ -102,6 +103,7 @@ CFILES = buf_mem.c \
        xfs_inode_fork.c \
        xfs_ialloc_btree.c \
        xfs_log_rlimit.c \
+       xfs_parent.c \
        xfs_refcount.c \
        xfs_refcount_btree.c \
        xfs_rmap.c \
index 1b3012413409365af035dabff5644d1088d6e9de..87b7c7964ecf94f359364138debf7bb583004742 100644 (file)
@@ -25,6 +25,7 @@
 #include "xfs_trans_space.h"
 #include "xfs_trace.h"
 #include "defer_item.h"
+#include "xfs_parent.h"
 
 struct kmem_cache              *xfs_attr_intent_cache;
 
@@ -1569,6 +1570,10 @@ xfs_attr_namecheck(
        if (length >= MAXNAMELEN)
                return false;
 
+       /* Parent pointers have their own validation. */
+       if (attr_flags & XFS_ATTR_PARENT)
+               return xfs_parent_namecheck(attr_flags, name, length);
+
        /* There shouldn't be any nulls here */
        return !memchr(name, 0, length);
 }
diff --git a/libxfs/xfs_parent.c b/libxfs/xfs_parent.c
new file mode 100644 (file)
index 0000000..c0ed7c5
--- /dev/null
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022-2024 Oracle.
+ * All rights reserved.
+ */
+#include "libxfs_priv.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_mount.h"
+#include "xfs_inode.h"
+#include "xfs_trans_resv.h"
+#include "xfs_mount.h"
+#include "xfs_trace.h"
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_da_format.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_trans.h"
+#include "xfs_da_btree.h"
+#include "xfs_attr.h"
+#include "xfs_dir2.h"
+#include "xfs_dir2_priv.h"
+#include "xfs_attr_sf.h"
+#include "xfs_bmap.h"
+#include "xfs_parent.h"
+#include "xfs_da_format.h"
+#include "xfs_format.h"
+#include "xfs_trans_space.h"
+
+/*
+ * Parent pointer attribute handling.
+ *
+ * Because the attribute name is a filename component, it will never be longer
+ * than 255 bytes and must not contain nulls or slashes.  These are roughly the
+ * same constraints that apply to attribute names.
+ *
+ * The attribute value must always be a struct xfs_parent_rec.  This means the
+ * attribute will never be in remote format because 12 bytes is nowhere near
+ * xfs_attr_leaf_entsize_local_max() (~75% of block size).
+ *
+ * Creating a new parent attribute will always create a new attribute - there
+ * should never, ever be an existing attribute in the tree for a new inode.
+ * ENOSPC behavior is problematic - creating the inode without the parent
+ * pointer is effectively a corruption, so we allow parent attribute creation
+ * to dip into the reserve block pool to avoid unexpected ENOSPC errors from
+ * occurring.
+ */
+
+/* Return true if parent pointer attr name is valid. */
+bool
+xfs_parent_namecheck(
+       unsigned int                    attr_flags,
+       const void                      *name,
+       size_t                          length)
+{
+       /*
+        * Parent pointers always use logged operations, so there should never
+        * be incomplete xattrs.
+        */
+       if (attr_flags & XFS_ATTR_INCOMPLETE)
+               return false;
+
+       return xfs_dir2_namecheck(name, length);
+}
+
+/* Return true if parent pointer attr value is valid. */
+bool
+xfs_parent_valuecheck(
+       struct xfs_mount                *mp,
+       const void                      *value,
+       size_t                          valuelen)
+{
+       const struct xfs_parent_rec     *rec = value;
+
+       if (!xfs_has_parent(mp))
+               return false;
+
+       /* The xattr value must be a parent record. */
+       if (valuelen != sizeof(struct xfs_parent_rec))
+               return false;
+
+       /* The parent record must be local. */
+       if (value == NULL)
+               return false;
+
+       /* The parent inumber must be valid. */
+       if (!xfs_verify_dir_ino(mp, be64_to_cpu(rec->p_ino)))
+               return false;
+
+       return true;
+}
diff --git a/libxfs/xfs_parent.h b/libxfs/xfs_parent.h
new file mode 100644 (file)
index 0000000..ef8aff8
--- /dev/null
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022-2024 Oracle.
+ * All Rights Reserved.
+ */
+#ifndef        __XFS_PARENT_H__
+#define        __XFS_PARENT_H__
+
+/* Metadata validators */
+bool xfs_parent_namecheck(unsigned int attr_flags, const void *name,
+               size_t length);
+bool xfs_parent_valuecheck(struct xfs_mount *mp, const void *value,
+               size_t valuelen);
+
+#endif /* __XFS_PARENT_H__ */