xref: /linux/fs/xfs/libxfs/xfs_parent.c (revision 5769aa41)
1a08d6729SAllison Henderson // SPDX-License-Identifier: GPL-2.0
2a08d6729SAllison Henderson /*
3a08d6729SAllison Henderson  * Copyright (c) 2022-2024 Oracle.
4a08d6729SAllison Henderson  * All rights reserved.
5a08d6729SAllison Henderson  */
6a08d6729SAllison Henderson #include "xfs.h"
7a08d6729SAllison Henderson #include "xfs_fs.h"
8a08d6729SAllison Henderson #include "xfs_format.h"
9a08d6729SAllison Henderson #include "xfs_da_format.h"
10a08d6729SAllison Henderson #include "xfs_log_format.h"
11a08d6729SAllison Henderson #include "xfs_shared.h"
12a08d6729SAllison Henderson #include "xfs_trans_resv.h"
13a08d6729SAllison Henderson #include "xfs_mount.h"
14a08d6729SAllison Henderson #include "xfs_bmap_btree.h"
15a08d6729SAllison Henderson #include "xfs_inode.h"
16a08d6729SAllison Henderson #include "xfs_error.h"
17a08d6729SAllison Henderson #include "xfs_trace.h"
18a08d6729SAllison Henderson #include "xfs_trans.h"
19a08d6729SAllison Henderson #include "xfs_da_btree.h"
20a08d6729SAllison Henderson #include "xfs_attr.h"
21a08d6729SAllison Henderson #include "xfs_dir2.h"
22a08d6729SAllison Henderson #include "xfs_dir2_priv.h"
23a08d6729SAllison Henderson #include "xfs_attr_sf.h"
24a08d6729SAllison Henderson #include "xfs_bmap.h"
25a08d6729SAllison Henderson #include "xfs_defer.h"
26a08d6729SAllison Henderson #include "xfs_log.h"
27a08d6729SAllison Henderson #include "xfs_xattr.h"
28a08d6729SAllison Henderson #include "xfs_parent.h"
29a08d6729SAllison Henderson #include "xfs_trans_space.h"
30b7c62d90SAllison Henderson #include "xfs_attr_item.h"
31b7c62d90SAllison Henderson #include "xfs_health.h"
32b7c62d90SAllison Henderson 
33b7c62d90SAllison Henderson struct kmem_cache		*xfs_parent_args_cache;
34a08d6729SAllison Henderson 
35a08d6729SAllison Henderson /*
36a08d6729SAllison Henderson  * Parent pointer attribute handling.
37a08d6729SAllison Henderson  *
38a08d6729SAllison Henderson  * Because the attribute name is a filename component, it will never be longer
39a08d6729SAllison Henderson  * than 255 bytes and must not contain nulls or slashes.  These are roughly the
40a08d6729SAllison Henderson  * same constraints that apply to attribute names.
41a08d6729SAllison Henderson  *
42a08d6729SAllison Henderson  * The attribute value must always be a struct xfs_parent_rec.  This means the
43a08d6729SAllison Henderson  * attribute will never be in remote format because 12 bytes is nowhere near
44a08d6729SAllison Henderson  * xfs_attr_leaf_entsize_local_max() (~75% of block size).
45a08d6729SAllison Henderson  *
46a08d6729SAllison Henderson  * Creating a new parent attribute will always create a new attribute - there
47a08d6729SAllison Henderson  * should never, ever be an existing attribute in the tree for a new inode.
48a08d6729SAllison Henderson  * ENOSPC behavior is problematic - creating the inode without the parent
49a08d6729SAllison Henderson  * pointer is effectively a corruption, so we allow parent attribute creation
50a08d6729SAllison Henderson  * to dip into the reserve block pool to avoid unexpected ENOSPC errors from
51a08d6729SAllison Henderson  * occurring.
52a08d6729SAllison Henderson  */
53a08d6729SAllison Henderson 
54a08d6729SAllison Henderson /* Return true if parent pointer attr name is valid. */
55a08d6729SAllison Henderson bool
xfs_parent_namecheck(unsigned int attr_flags,const void * name,size_t length)56a08d6729SAllison Henderson xfs_parent_namecheck(
57a08d6729SAllison Henderson 	unsigned int			attr_flags,
58a08d6729SAllison Henderson 	const void			*name,
59a08d6729SAllison Henderson 	size_t				length)
60a08d6729SAllison Henderson {
61a08d6729SAllison Henderson 	/*
62a08d6729SAllison Henderson 	 * Parent pointers always use logged operations, so there should never
63a08d6729SAllison Henderson 	 * be incomplete xattrs.
64a08d6729SAllison Henderson 	 */
65a08d6729SAllison Henderson 	if (attr_flags & XFS_ATTR_INCOMPLETE)
66a08d6729SAllison Henderson 		return false;
67a08d6729SAllison Henderson 
68a08d6729SAllison Henderson 	return xfs_dir2_namecheck(name, length);
69a08d6729SAllison Henderson }
70a08d6729SAllison Henderson 
71a08d6729SAllison Henderson /* Return true if parent pointer attr value is valid. */
72a08d6729SAllison Henderson bool
xfs_parent_valuecheck(struct xfs_mount * mp,const void * value,size_t valuelen)73a08d6729SAllison Henderson xfs_parent_valuecheck(
74a08d6729SAllison Henderson 	struct xfs_mount		*mp,
75a08d6729SAllison Henderson 	const void			*value,
76a08d6729SAllison Henderson 	size_t				valuelen)
77a08d6729SAllison Henderson {
78a08d6729SAllison Henderson 	const struct xfs_parent_rec	*rec = value;
79a08d6729SAllison Henderson 
80a08d6729SAllison Henderson 	if (!xfs_has_parent(mp))
81a08d6729SAllison Henderson 		return false;
82a08d6729SAllison Henderson 
83a08d6729SAllison Henderson 	/* The xattr value must be a parent record. */
84a08d6729SAllison Henderson 	if (valuelen != sizeof(struct xfs_parent_rec))
85a08d6729SAllison Henderson 		return false;
86a08d6729SAllison Henderson 
87a08d6729SAllison Henderson 	/* The parent record must be local. */
88a08d6729SAllison Henderson 	if (value == NULL)
89a08d6729SAllison Henderson 		return false;
90a08d6729SAllison Henderson 
91a08d6729SAllison Henderson 	/* The parent inumber must be valid. */
92a08d6729SAllison Henderson 	if (!xfs_verify_dir_ino(mp, be64_to_cpu(rec->p_ino)))
93a08d6729SAllison Henderson 		return false;
94a08d6729SAllison Henderson 
95a08d6729SAllison Henderson 	return true;
96a08d6729SAllison Henderson }
97fb102fe7SDarrick J. Wong 
98fb102fe7SDarrick J. Wong /* Compute the attribute name hash for a parent pointer. */
99fb102fe7SDarrick J. Wong xfs_dahash_t
xfs_parent_hashval(struct xfs_mount * mp,const uint8_t * name,int namelen,xfs_ino_t parent_ino)100fb102fe7SDarrick J. Wong xfs_parent_hashval(
101fb102fe7SDarrick J. Wong 	struct xfs_mount		*mp,
102fb102fe7SDarrick J. Wong 	const uint8_t			*name,
103fb102fe7SDarrick J. Wong 	int				namelen,
104fb102fe7SDarrick J. Wong 	xfs_ino_t			parent_ino)
105fb102fe7SDarrick J. Wong {
106fb102fe7SDarrick J. Wong 	struct xfs_name			xname = {
107fb102fe7SDarrick J. Wong 		.name			= name,
108fb102fe7SDarrick J. Wong 		.len			= namelen,
109fb102fe7SDarrick J. Wong 	};
110fb102fe7SDarrick J. Wong 
111fb102fe7SDarrick J. Wong 	/*
112fb102fe7SDarrick J. Wong 	 * Use the same dirent name hash as would be used on the directory, but
113fb102fe7SDarrick J. Wong 	 * mix in the parent inode number to avoid collisions on hardlinked
114fb102fe7SDarrick J. Wong 	 * files with identical names but different parents.
115fb102fe7SDarrick J. Wong 	 */
116fb102fe7SDarrick J. Wong 	return xfs_dir2_hashname(mp, &xname) ^
117fb102fe7SDarrick J. Wong 		upper_32_bits(parent_ino) ^ lower_32_bits(parent_ino);
118fb102fe7SDarrick J. Wong }
119fb102fe7SDarrick J. Wong 
120fb102fe7SDarrick J. Wong /* Compute the attribute name hash from the xattr components. */
121fb102fe7SDarrick J. Wong xfs_dahash_t
xfs_parent_hashattr(struct xfs_mount * mp,const uint8_t * name,int namelen,const void * value,int valuelen)122fb102fe7SDarrick J. Wong xfs_parent_hashattr(
123fb102fe7SDarrick J. Wong 	struct xfs_mount		*mp,
124fb102fe7SDarrick J. Wong 	const uint8_t			*name,
125fb102fe7SDarrick J. Wong 	int				namelen,
126fb102fe7SDarrick J. Wong 	const void			*value,
127fb102fe7SDarrick J. Wong 	int				valuelen)
128fb102fe7SDarrick J. Wong {
129fb102fe7SDarrick J. Wong 	const struct xfs_parent_rec	*rec = value;
130fb102fe7SDarrick J. Wong 
131fb102fe7SDarrick J. Wong 	/* Requires a local attr value in xfs_parent_rec format */
132fb102fe7SDarrick J. Wong 	if (valuelen != sizeof(struct xfs_parent_rec)) {
133fb102fe7SDarrick J. Wong 		ASSERT(valuelen == sizeof(struct xfs_parent_rec));
134fb102fe7SDarrick J. Wong 		return 0;
135fb102fe7SDarrick J. Wong 	}
136fb102fe7SDarrick J. Wong 
137fb102fe7SDarrick J. Wong 	if (!value) {
138fb102fe7SDarrick J. Wong 		ASSERT(value != NULL);
139fb102fe7SDarrick J. Wong 		return 0;
140fb102fe7SDarrick J. Wong 	}
141fb102fe7SDarrick J. Wong 
142fb102fe7SDarrick J. Wong 	return xfs_parent_hashval(mp, name, namelen, be64_to_cpu(rec->p_ino));
143fb102fe7SDarrick J. Wong }
144b7c62d90SAllison Henderson 
145b7c62d90SAllison Henderson /*
146b7c62d90SAllison Henderson  * Initialize the parent pointer arguments structure.  Caller must have zeroed
147b7c62d90SAllison Henderson  * the contents of @args.  @tp is only required for updates.
148b7c62d90SAllison Henderson  */
149b7c62d90SAllison Henderson static void
xfs_parent_da_args_init(struct xfs_da_args * args,struct xfs_trans * tp,struct xfs_parent_rec * rec,struct xfs_inode * child,xfs_ino_t owner,const struct xfs_name * parent_name)150b7c62d90SAllison Henderson xfs_parent_da_args_init(
151b7c62d90SAllison Henderson 	struct xfs_da_args	*args,
152b7c62d90SAllison Henderson 	struct xfs_trans	*tp,
153b7c62d90SAllison Henderson 	struct xfs_parent_rec	*rec,
154b7c62d90SAllison Henderson 	struct xfs_inode	*child,
155b7c62d90SAllison Henderson 	xfs_ino_t		owner,
156b7c62d90SAllison Henderson 	const struct xfs_name	*parent_name)
157b7c62d90SAllison Henderson {
158b7c62d90SAllison Henderson 	args->geo = child->i_mount->m_attr_geo;
159b7c62d90SAllison Henderson 	args->whichfork = XFS_ATTR_FORK;
160b7c62d90SAllison Henderson 	args->attr_filter = XFS_ATTR_PARENT;
161b7c62d90SAllison Henderson 	args->op_flags = XFS_DA_OP_LOGGED | XFS_DA_OP_OKNOENT;
162b7c62d90SAllison Henderson 	args->trans = tp;
163b7c62d90SAllison Henderson 	args->dp = child;
164b7c62d90SAllison Henderson 	args->owner = owner;
165b7c62d90SAllison Henderson 	args->name = parent_name->name;
166b7c62d90SAllison Henderson 	args->namelen = parent_name->len;
167b7c62d90SAllison Henderson 	args->value = rec;
168b7c62d90SAllison Henderson 	args->valuelen = sizeof(struct xfs_parent_rec);
169b7c62d90SAllison Henderson 	xfs_attr_sethash(args);
170b7c62d90SAllison Henderson }
171b7c62d90SAllison Henderson 
172b7c62d90SAllison Henderson /* Make sure the incore state is ready for a parent pointer query/update. */
173b7c62d90SAllison Henderson static inline int
xfs_parent_iread_extents(struct xfs_trans * tp,struct xfs_inode * child)174b7c62d90SAllison Henderson xfs_parent_iread_extents(
175b7c62d90SAllison Henderson 	struct xfs_trans	*tp,
176b7c62d90SAllison Henderson 	struct xfs_inode	*child)
177b7c62d90SAllison Henderson {
178b7c62d90SAllison Henderson 	/* Parent pointers require that the attr fork must exist. */
179b7c62d90SAllison Henderson 	if (XFS_IS_CORRUPT(child->i_mount, !xfs_inode_has_attr_fork(child))) {
180b7c62d90SAllison Henderson 		xfs_inode_mark_sick(child, XFS_SICK_INO_PARENT);
181b7c62d90SAllison Henderson 		return -EFSCORRUPTED;
182b7c62d90SAllison Henderson 	}
183b7c62d90SAllison Henderson 
184b7c62d90SAllison Henderson 	return xfs_iread_extents(tp, child, XFS_ATTR_FORK);
185b7c62d90SAllison Henderson }
186b7c62d90SAllison Henderson 
187b7c62d90SAllison Henderson /* Add a parent pointer to reflect a dirent addition. */
188b7c62d90SAllison Henderson int
xfs_parent_addname(struct xfs_trans * tp,struct xfs_parent_args * ppargs,struct xfs_inode * dp,const struct xfs_name * parent_name,struct xfs_inode * child)189b7c62d90SAllison Henderson xfs_parent_addname(
190b7c62d90SAllison Henderson 	struct xfs_trans	*tp,
191b7c62d90SAllison Henderson 	struct xfs_parent_args	*ppargs,
192b7c62d90SAllison Henderson 	struct xfs_inode	*dp,
193b7c62d90SAllison Henderson 	const struct xfs_name	*parent_name,
194b7c62d90SAllison Henderson 	struct xfs_inode	*child)
195b7c62d90SAllison Henderson {
196b7c62d90SAllison Henderson 	int			error;
197b7c62d90SAllison Henderson 
198b7c62d90SAllison Henderson 	error = xfs_parent_iread_extents(tp, child);
199b7c62d90SAllison Henderson 	if (error)
200b7c62d90SAllison Henderson 		return error;
201b7c62d90SAllison Henderson 
202b7c62d90SAllison Henderson 	xfs_inode_to_parent_rec(&ppargs->rec, dp);
203b7c62d90SAllison Henderson 	xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child,
204b7c62d90SAllison Henderson 			child->i_ino, parent_name);
205b7c62d90SAllison Henderson 	xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_SET);
206b7c62d90SAllison Henderson 	return 0;
207b7c62d90SAllison Henderson }
208d2d18330SAllison Henderson 
209d2d18330SAllison Henderson /* Remove a parent pointer to reflect a dirent removal. */
210d2d18330SAllison Henderson int
xfs_parent_removename(struct xfs_trans * tp,struct xfs_parent_args * ppargs,struct xfs_inode * dp,const struct xfs_name * parent_name,struct xfs_inode * child)211d2d18330SAllison Henderson xfs_parent_removename(
212d2d18330SAllison Henderson 	struct xfs_trans	*tp,
213d2d18330SAllison Henderson 	struct xfs_parent_args	*ppargs,
214d2d18330SAllison Henderson 	struct xfs_inode	*dp,
215d2d18330SAllison Henderson 	const struct xfs_name	*parent_name,
216d2d18330SAllison Henderson 	struct xfs_inode	*child)
217d2d18330SAllison Henderson {
218d2d18330SAllison Henderson 	int			error;
219d2d18330SAllison Henderson 
220d2d18330SAllison Henderson 	error = xfs_parent_iread_extents(tp, child);
221d2d18330SAllison Henderson 	if (error)
222d2d18330SAllison Henderson 		return error;
223d2d18330SAllison Henderson 
224d2d18330SAllison Henderson 	xfs_inode_to_parent_rec(&ppargs->rec, dp);
225d2d18330SAllison Henderson 	xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child,
226d2d18330SAllison Henderson 			child->i_ino, parent_name);
227d2d18330SAllison Henderson 	xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_REMOVE);
228d2d18330SAllison Henderson 	return 0;
229d2d18330SAllison Henderson }
2305a8338c8SAllison Henderson 
2315a8338c8SAllison Henderson /* Replace one parent pointer with another to reflect a rename. */
2325a8338c8SAllison Henderson int
xfs_parent_replacename(struct xfs_trans * tp,struct xfs_parent_args * ppargs,struct xfs_inode * old_dp,const struct xfs_name * old_name,struct xfs_inode * new_dp,const struct xfs_name * new_name,struct xfs_inode * child)2335a8338c8SAllison Henderson xfs_parent_replacename(
2345a8338c8SAllison Henderson 	struct xfs_trans	*tp,
2355a8338c8SAllison Henderson 	struct xfs_parent_args	*ppargs,
2365a8338c8SAllison Henderson 	struct xfs_inode	*old_dp,
2375a8338c8SAllison Henderson 	const struct xfs_name	*old_name,
2385a8338c8SAllison Henderson 	struct xfs_inode	*new_dp,
2395a8338c8SAllison Henderson 	const struct xfs_name	*new_name,
2405a8338c8SAllison Henderson 	struct xfs_inode	*child)
2415a8338c8SAllison Henderson {
2425a8338c8SAllison Henderson 	int			error;
2435a8338c8SAllison Henderson 
2445a8338c8SAllison Henderson 	error = xfs_parent_iread_extents(tp, child);
2455a8338c8SAllison Henderson 	if (error)
2465a8338c8SAllison Henderson 		return error;
2475a8338c8SAllison Henderson 
2485a8338c8SAllison Henderson 	xfs_inode_to_parent_rec(&ppargs->rec, old_dp);
2495a8338c8SAllison Henderson 	xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child,
2505a8338c8SAllison Henderson 			child->i_ino, old_name);
2515a8338c8SAllison Henderson 
2525a8338c8SAllison Henderson 	xfs_inode_to_parent_rec(&ppargs->new_rec, new_dp);
2535a8338c8SAllison Henderson 	ppargs->args.new_name = new_name->name;
2545a8338c8SAllison Henderson 	ppargs->args.new_namelen = new_name->len;
2555a8338c8SAllison Henderson 	ppargs->args.new_value = &ppargs->new_rec;
2565a8338c8SAllison Henderson 	ppargs->args.new_valuelen = sizeof(struct xfs_parent_rec);
2575a8338c8SAllison Henderson 	xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_REPLACE);
2585a8338c8SAllison Henderson 	return 0;
2595a8338c8SAllison Henderson }
260233f4e12SDarrick J. Wong 
261233f4e12SDarrick J. Wong /*
262233f4e12SDarrick J. Wong  * Extract parent pointer information from any parent pointer xattr into
263233f4e12SDarrick J. Wong  * @parent_ino/gen.  The last two parameters can be NULL pointers.
264233f4e12SDarrick J. Wong  *
265233f4e12SDarrick J. Wong  * Returns 0 if this is not a parent pointer xattr at all; or -EFSCORRUPTED for
266233f4e12SDarrick J. Wong  * garbage.
267233f4e12SDarrick J. Wong  */
268233f4e12SDarrick J. Wong 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)269233f4e12SDarrick J. Wong xfs_parent_from_attr(
270233f4e12SDarrick J. Wong 	struct xfs_mount	*mp,
271233f4e12SDarrick J. Wong 	unsigned int		attr_flags,
272233f4e12SDarrick J. Wong 	const unsigned char	*name,
273233f4e12SDarrick J. Wong 	unsigned int		namelen,
274233f4e12SDarrick J. Wong 	const void		*value,
275233f4e12SDarrick J. Wong 	unsigned int		valuelen,
276233f4e12SDarrick J. Wong 	xfs_ino_t		*parent_ino,
277233f4e12SDarrick J. Wong 	uint32_t		*parent_gen)
278233f4e12SDarrick J. Wong {
279233f4e12SDarrick J. Wong 	const struct xfs_parent_rec	*rec = value;
280233f4e12SDarrick J. Wong 
281233f4e12SDarrick J. Wong 	ASSERT(attr_flags & XFS_ATTR_PARENT);
282233f4e12SDarrick J. Wong 
283233f4e12SDarrick J. Wong 	if (!xfs_parent_namecheck(attr_flags, name, namelen))
284233f4e12SDarrick J. Wong 		return -EFSCORRUPTED;
285233f4e12SDarrick J. Wong 	if (!xfs_parent_valuecheck(mp, value, valuelen))
286233f4e12SDarrick J. Wong 		return -EFSCORRUPTED;
287233f4e12SDarrick J. Wong 
288233f4e12SDarrick J. Wong 	if (parent_ino)
289233f4e12SDarrick J. Wong 		*parent_ino = be64_to_cpu(rec->p_ino);
290233f4e12SDarrick J. Wong 	if (parent_gen)
291233f4e12SDarrick J. Wong 		*parent_gen = be32_to_cpu(rec->p_gen);
292233f4e12SDarrick J. Wong 	return 0;
293233f4e12SDarrick J. Wong }
29461b3f0dfSDarrick J. Wong 
29561b3f0dfSDarrick J. Wong /*
29661b3f0dfSDarrick J. Wong  * Look up a parent pointer record (@parent_name -> @pptr) of @ip.
29761b3f0dfSDarrick J. Wong  *
29861b3f0dfSDarrick J. Wong  * Caller must hold at least ILOCK_SHARED.  The scratchpad need not be
29961b3f0dfSDarrick J. Wong  * initialized.
30061b3f0dfSDarrick J. Wong  *
30161b3f0dfSDarrick J. Wong  * Returns 0 if the pointer is found, -ENOATTR if there is no match, or a
30261b3f0dfSDarrick J. Wong  * negative errno.
30361b3f0dfSDarrick J. Wong  */
30461b3f0dfSDarrick J. Wong int
xfs_parent_lookup(struct xfs_trans * tp,struct xfs_inode * ip,const struct xfs_name * parent_name,struct xfs_parent_rec * pptr,struct xfs_da_args * scratch)30561b3f0dfSDarrick J. Wong xfs_parent_lookup(
30661b3f0dfSDarrick J. Wong 	struct xfs_trans		*tp,
30761b3f0dfSDarrick J. Wong 	struct xfs_inode		*ip,
30861b3f0dfSDarrick J. Wong 	const struct xfs_name		*parent_name,
30961b3f0dfSDarrick J. Wong 	struct xfs_parent_rec		*pptr,
31061b3f0dfSDarrick J. Wong 	struct xfs_da_args		*scratch)
31161b3f0dfSDarrick J. Wong {
31261b3f0dfSDarrick J. Wong 	memset(scratch, 0, sizeof(struct xfs_da_args));
31361b3f0dfSDarrick J. Wong 	xfs_parent_da_args_init(scratch, tp, pptr, ip, ip->i_ino, parent_name);
31461b3f0dfSDarrick J. Wong 	return xfs_attr_get_ilocked(scratch);
31561b3f0dfSDarrick J. Wong }
316*5769aa41SDarrick J. Wong 
317*5769aa41SDarrick J. Wong /* Sanity-check a parent pointer before we try to perform repairs. */
318*5769aa41SDarrick J. Wong static inline bool
xfs_parent_sanity_check(struct xfs_mount * mp,const struct xfs_name * parent_name,const struct xfs_parent_rec * pptr)319*5769aa41SDarrick J. Wong xfs_parent_sanity_check(
320*5769aa41SDarrick J. Wong 	struct xfs_mount		*mp,
321*5769aa41SDarrick J. Wong 	const struct xfs_name		*parent_name,
322*5769aa41SDarrick J. Wong 	const struct xfs_parent_rec	*pptr)
323*5769aa41SDarrick J. Wong {
324*5769aa41SDarrick J. Wong 	if (!xfs_parent_namecheck(XFS_ATTR_PARENT, parent_name->name,
325*5769aa41SDarrick J. Wong 				parent_name->len))
326*5769aa41SDarrick J. Wong 		return false;
327*5769aa41SDarrick J. Wong 
328*5769aa41SDarrick J. Wong 	if (!xfs_parent_valuecheck(mp, pptr, sizeof(*pptr)))
329*5769aa41SDarrick J. Wong 		return false;
330*5769aa41SDarrick J. Wong 
331*5769aa41SDarrick J. Wong 	return true;
332*5769aa41SDarrick J. Wong }
333*5769aa41SDarrick J. Wong 
334*5769aa41SDarrick J. Wong 
335*5769aa41SDarrick J. Wong /*
336*5769aa41SDarrick J. Wong  * Attach the parent pointer (@parent_name -> @pptr) to @ip immediately.
337*5769aa41SDarrick J. Wong  * Caller must not have a transaction or hold the ILOCK.  This is for
338*5769aa41SDarrick J. Wong  * specialized repair functions only.  The scratchpad need not be initialized.
339*5769aa41SDarrick J. Wong  */
340*5769aa41SDarrick J. Wong int
xfs_parent_set(struct xfs_inode * ip,xfs_ino_t owner,const struct xfs_name * parent_name,struct xfs_parent_rec * pptr,struct xfs_da_args * scratch)341*5769aa41SDarrick J. Wong xfs_parent_set(
342*5769aa41SDarrick J. Wong 	struct xfs_inode	*ip,
343*5769aa41SDarrick J. Wong 	xfs_ino_t		owner,
344*5769aa41SDarrick J. Wong 	const struct xfs_name	*parent_name,
345*5769aa41SDarrick J. Wong 	struct xfs_parent_rec	*pptr,
346*5769aa41SDarrick J. Wong 	struct xfs_da_args	*scratch)
347*5769aa41SDarrick J. Wong {
348*5769aa41SDarrick J. Wong 	if (!xfs_parent_sanity_check(ip->i_mount, parent_name, pptr)) {
349*5769aa41SDarrick J. Wong 		ASSERT(0);
350*5769aa41SDarrick J. Wong 		return -EFSCORRUPTED;
351*5769aa41SDarrick J. Wong 	}
352*5769aa41SDarrick J. Wong 
353*5769aa41SDarrick J. Wong 	memset(scratch, 0, sizeof(struct xfs_da_args));
354*5769aa41SDarrick J. Wong 	xfs_parent_da_args_init(scratch, NULL, pptr, ip, owner, parent_name);
355*5769aa41SDarrick J. Wong 	return xfs_attr_set(scratch, XFS_ATTRUPDATE_CREATE, false);
356*5769aa41SDarrick J. Wong }
357*5769aa41SDarrick J. Wong 
358*5769aa41SDarrick J. Wong /*
359*5769aa41SDarrick J. Wong  * Remove the parent pointer (@parent_name -> @pptr) from @ip immediately.
360*5769aa41SDarrick J. Wong  * Caller must not have a transaction or hold the ILOCK.  This is for
361*5769aa41SDarrick J. Wong  * specialized repair functions only.  The scratchpad need not be initialized.
362*5769aa41SDarrick J. Wong  */
363*5769aa41SDarrick J. Wong int
xfs_parent_unset(struct xfs_inode * ip,xfs_ino_t owner,const struct xfs_name * parent_name,struct xfs_parent_rec * pptr,struct xfs_da_args * scratch)364*5769aa41SDarrick J. Wong xfs_parent_unset(
365*5769aa41SDarrick J. Wong 	struct xfs_inode		*ip,
366*5769aa41SDarrick J. Wong 	xfs_ino_t			owner,
367*5769aa41SDarrick J. Wong 	const struct xfs_name		*parent_name,
368*5769aa41SDarrick J. Wong 	struct xfs_parent_rec		*pptr,
369*5769aa41SDarrick J. Wong 	struct xfs_da_args		*scratch)
370*5769aa41SDarrick J. Wong {
371*5769aa41SDarrick J. Wong 	if (!xfs_parent_sanity_check(ip->i_mount, parent_name, pptr)) {
372*5769aa41SDarrick J. Wong 		ASSERT(0);
373*5769aa41SDarrick J. Wong 		return -EFSCORRUPTED;
374*5769aa41SDarrick J. Wong 	}
375*5769aa41SDarrick J. Wong 
376*5769aa41SDarrick J. Wong 	memset(scratch, 0, sizeof(struct xfs_da_args));
377*5769aa41SDarrick J. Wong 	xfs_parent_da_args_init(scratch, NULL, pptr, ip, owner, parent_name);
378*5769aa41SDarrick J. Wong 	return xfs_attr_set(scratch, XFS_ATTRUPDATE_REMOVE, false);
379*5769aa41SDarrick J. Wong }
380