File Index
Files and directories
Sign in
FILE

xfs_parent.c

File preview with syntax highlighting.

linux-6.19.14/fs/xfs/libxfs/xfs_parent.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (c) 2022-2024 Oracle.
  4 * All rights reserved.
  5 */
  6#include "xfs.h"
  7#include "xfs_fs.h"
  8#include "xfs_format.h"
  9#include "xfs_da_format.h"
 10#include "xfs_log_format.h"
 11#include "xfs_shared.h"
 12#include "xfs_trans_resv.h"
 13#include "xfs_mount.h"
 14#include "xfs_bmap_btree.h"
 15#include "xfs_inode.h"
 16#include "xfs_error.h"
 17#include "xfs_trace.h"
 18#include "xfs_trans.h"
 19#include "xfs_da_btree.h"
 20#include "xfs_attr.h"
 21#include "xfs_dir2.h"
 22#include "xfs_dir2_priv.h"
 23#include "xfs_attr_sf.h"
 24#include "xfs_bmap.h"
 25#include "xfs_defer.h"
 26#include "xfs_log.h"
 27#include "xfs_xattr.h"
 28#include "xfs_parent.h"
 29#include "xfs_trans_space.h"
 30#include "xfs_attr_item.h"
 31#include "xfs_health.h"
 32
 33struct kmem_cache		*xfs_parent_args_cache;
 34
 35/*
 36 * Parent pointer attribute handling.
 37 *
 38 * Because the attribute name is a filename component, it will never be longer
 39 * than 255 bytes and must not contain nulls or slashes.  These are roughly the
 40 * same constraints that apply to attribute names.
 41 *
 42 * The attribute value must always be a struct xfs_parent_rec.  This means the
 43 * attribute will never be in remote format because 12 bytes is nowhere near
 44 * xfs_attr_leaf_entsize_local_max() (~75% of block size).
 45 *
 46 * Creating a new parent attribute will always create a new attribute - there
 47 * should never, ever be an existing attribute in the tree for a new inode.
 48 * ENOSPC behavior is problematic - creating the inode without the parent
 49 * pointer is effectively a corruption, so we allow parent attribute creation
 50 * to dip into the reserve block pool to avoid unexpected ENOSPC errors from
 51 * occurring.
 52 */
 53
 54/* Return true if parent pointer attr name is valid. */
 55bool
 56xfs_parent_namecheck(
 57	unsigned int			attr_flags,
 58	const void			*name,
 59	size_t				length)
 60{
 61	/*
 62	 * Parent pointers always use logged operations, so there should never
 63	 * be incomplete xattrs.
 64	 */
 65	if (attr_flags & XFS_ATTR_INCOMPLETE)
 66		return false;
 67
 68	return xfs_dir2_namecheck(name, length);
 69}
 70
 71/* Return true if parent pointer attr value is valid. */
 72bool
 73xfs_parent_valuecheck(
 74	struct xfs_mount		*mp,
 75	const void			*value,
 76	size_t				valuelen)
 77{
 78	const struct xfs_parent_rec	*rec = value;
 79
 80	if (!xfs_has_parent(mp))
 81		return false;
 82
 83	/* The xattr value must be a parent record. */
 84	if (valuelen != sizeof(struct xfs_parent_rec))
 85		return false;
 86
 87	/* The parent record must be local. */
 88	if (value == NULL)
 89		return false;
 90
 91	/* The parent inumber must be valid. */
 92	if (!xfs_verify_dir_ino(mp, be64_to_cpu(rec->p_ino)))
 93		return false;
 94
 95	return true;
 96}
 97
 98/* Compute the attribute name hash for a parent pointer. */
 99xfs_dahash_t
100xfs_parent_hashval(
101	struct xfs_mount		*mp,
102	const uint8_t			*name,
103	int				namelen,
104	xfs_ino_t			parent_ino)
105{
106	struct xfs_name			xname = {
107		.name			= name,
108		.len			= namelen,
109	};
110
111	/*
112	 * Use the same dirent name hash as would be used on the directory, but
113	 * mix in the parent inode number to avoid collisions on hardlinked
114	 * files with identical names but different parents.
115	 */
116	return xfs_dir2_hashname(mp, &xname) ^
117		upper_32_bits(parent_ino) ^ lower_32_bits(parent_ino);
118}
119
120/* Compute the attribute name hash from the xattr components. */
121xfs_dahash_t
122xfs_parent_hashattr(
123	struct xfs_mount		*mp,
124	const uint8_t			*name,
125	int				namelen,
126	const void			*value,
127	int				valuelen)
128{
129	const struct xfs_parent_rec	*rec = value;
130
131	/* Requires a local attr value in xfs_parent_rec format */
132	if (valuelen != sizeof(struct xfs_parent_rec)) {
133		ASSERT(valuelen == sizeof(struct xfs_parent_rec));
134		return 0;
135	}
136
137	if (!value) {
138		ASSERT(value != NULL);
139		return 0;
140	}
141
142	return xfs_parent_hashval(mp, name, namelen, be64_to_cpu(rec->p_ino));
143}
144
145/*
146 * Initialize the parent pointer arguments structure.  Caller must have zeroed
147 * the contents of @args.  @tp is only required for updates.
148 */
149static void
150xfs_parent_da_args_init(
151	struct xfs_da_args	*args,
152	struct xfs_trans	*tp,
153	struct xfs_parent_rec	*rec,
154	struct xfs_inode	*child,
155	xfs_ino_t		owner,
156	const struct xfs_name	*parent_name)
157{
158	args->geo = child->i_mount->m_attr_geo;
159	args->whichfork = XFS_ATTR_FORK;
160	args->attr_filter = XFS_ATTR_PARENT;
161	args->op_flags = XFS_DA_OP_LOGGED | XFS_DA_OP_OKNOENT;
162	args->trans = tp;
163	args->dp = child;
164	args->owner = owner;
165	args->name = parent_name->name;
166	args->namelen = parent_name->len;
167	args->value = rec;
168	args->valuelen = sizeof(struct xfs_parent_rec);
169	xfs_attr_sethash(args);
170}
171
172/* Make sure the incore state is ready for a parent pointer query/update. */
173static inline int
174xfs_parent_iread_extents(
175	struct xfs_trans	*tp,
176	struct xfs_inode	*child)
177{
178	/* Parent pointers require that the attr fork must exist. */
179	if (XFS_IS_CORRUPT(child->i_mount, !xfs_inode_has_attr_fork(child))) {
180		xfs_inode_mark_sick(child, XFS_SICK_INO_PARENT);
181		return -EFSCORRUPTED;
182	}
183
184	return xfs_iread_extents(tp, child, XFS_ATTR_FORK);
185}
186
187/* Add a parent pointer to reflect a dirent addition. */
188int
189xfs_parent_addname(
190	struct xfs_trans	*tp,
191	struct xfs_parent_args	*ppargs,
192	struct xfs_inode	*dp,
193	const struct xfs_name	*parent_name,
194	struct xfs_inode	*child)
195{
196	int			error;
197
198	error = xfs_parent_iread_extents(tp, child);
199	if (error)
200		return error;
201
202	xfs_inode_to_parent_rec(&ppargs->rec, dp);
203	xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child,
204			child->i_ino, parent_name);
205	xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_SET);
206	return 0;
207}
208
209/* Remove a parent pointer to reflect a dirent removal. */
210int
211xfs_parent_removename(
212	struct xfs_trans	*tp,
213	struct xfs_parent_args	*ppargs,
214	struct xfs_inode	*dp,
215	const struct xfs_name	*parent_name,
216	struct xfs_inode	*child)
217{
218	int			error;
219
220	error = xfs_parent_iread_extents(tp, child);
221	if (error)
222		return error;
223
224	xfs_inode_to_parent_rec(&ppargs->rec, dp);
225	xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child,
226			child->i_ino, parent_name);
227	xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_REMOVE);
228	return 0;
229}
230
231/* Replace one parent pointer with another to reflect a rename. */
232int
233xfs_parent_replacename(
234	struct xfs_trans	*tp,
235	struct xfs_parent_args	*ppargs,
236	struct xfs_inode	*old_dp,
237	const struct xfs_name	*old_name,
238	struct xfs_inode	*new_dp,
239	const struct xfs_name	*new_name,
240	struct xfs_inode	*child)
241{
242	int			error;
243
244	error = xfs_parent_iread_extents(tp, child);
245	if (error)
246		return error;
247
248	xfs_inode_to_parent_rec(&ppargs->rec, old_dp);
249	xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child,
250			child->i_ino, old_name);
251
252	xfs_inode_to_parent_rec(&ppargs->new_rec, new_dp);
253	ppargs->args.new_name = new_name->name;
254	ppargs->args.new_namelen = new_name->len;
255	ppargs->args.new_value = &ppargs->new_rec;
256	ppargs->args.new_valuelen = sizeof(struct xfs_parent_rec);
257	xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_REPLACE);
258	return 0;
259}
260
261/*
262 * Extract parent pointer information from any parent pointer xattr into
263 * @parent_ino/gen.  The last two parameters can be NULL pointers.
264 *
265 * Returns 0 if this is not a parent pointer xattr at all; or -EFSCORRUPTED for
266 * garbage.
267 */
268int
269xfs_parent_from_attr(
270	struct xfs_mount	*mp,
271	unsigned int		attr_flags,
272	const unsigned char	*name,
273	unsigned int		namelen,
274	const void		*value,
275	unsigned int		valuelen,
276	xfs_ino_t		*parent_ino,
277	uint32_t		*parent_gen)
278{
279	const struct xfs_parent_rec	*rec = value;
280
281	ASSERT(attr_flags & XFS_ATTR_PARENT);
282
283	if (!xfs_parent_namecheck(attr_flags, name, namelen))
284		return -EFSCORRUPTED;
285	if (!xfs_parent_valuecheck(mp, value, valuelen))
286		return -EFSCORRUPTED;
287
288	if (parent_ino)
289		*parent_ino = be64_to_cpu(rec->p_ino);
290	if (parent_gen)
291		*parent_gen = be32_to_cpu(rec->p_gen);
292	return 0;
293}
294
295/*
296 * Look up a parent pointer record (@parent_name -> @pptr) of @ip.
297 *
298 * Caller must hold at least ILOCK_SHARED.  The scratchpad need not be
299 * initialized.
300 *
301 * Returns 0 if the pointer is found, -ENOATTR if there is no match, or a
302 * negative errno.
303 */
304int
305xfs_parent_lookup(
306	struct xfs_trans		*tp,
307	struct xfs_inode		*ip,
308	const struct xfs_name		*parent_name,
309	struct xfs_parent_rec		*pptr,
310	struct xfs_da_args		*scratch)
311{
312	memset(scratch, 0, sizeof(struct xfs_da_args));
313	xfs_parent_da_args_init(scratch, tp, pptr, ip, ip->i_ino, parent_name);
314	return xfs_attr_get_ilocked(scratch);
315}
316
317/* Sanity-check a parent pointer before we try to perform repairs. */
318static inline bool
319xfs_parent_sanity_check(
320	struct xfs_mount		*mp,
321	const struct xfs_name		*parent_name,
322	const struct xfs_parent_rec	*pptr)
323{
324	if (!xfs_parent_namecheck(XFS_ATTR_PARENT, parent_name->name,
325				parent_name->len))
326		return false;
327
328	if (!xfs_parent_valuecheck(mp, pptr, sizeof(*pptr)))
329		return false;
330
331	return true;
332}
333
334
335/*
336 * Attach the parent pointer (@parent_name -> @pptr) to @ip immediately.
337 * Caller must not have a transaction or hold the ILOCK.  This is for
338 * specialized repair functions only.  The scratchpad need not be initialized.
339 */
340int
341xfs_parent_set(
342	struct xfs_inode	*ip,
343	xfs_ino_t		owner,
344	const struct xfs_name	*parent_name,
345	struct xfs_parent_rec	*pptr,
346	struct xfs_da_args	*scratch)
347{
348	if (!xfs_parent_sanity_check(ip->i_mount, parent_name, pptr)) {
349		ASSERT(0);
350		return -EFSCORRUPTED;
351	}
352
353	memset(scratch, 0, sizeof(struct xfs_da_args));
354	xfs_parent_da_args_init(scratch, NULL, pptr, ip, owner, parent_name);
355	return xfs_attr_set(scratch, XFS_ATTRUPDATE_CREATE, false);
356}
357
358/*
359 * Remove the parent pointer (@parent_name -> @pptr) from @ip immediately.
360 * Caller must not have a transaction or hold the ILOCK.  This is for
361 * specialized repair functions only.  The scratchpad need not be initialized.
362 */
363int
364xfs_parent_unset(
365	struct xfs_inode		*ip,
366	xfs_ino_t			owner,
367	const struct xfs_name		*parent_name,
368	struct xfs_parent_rec		*pptr,
369	struct xfs_da_args		*scratch)
370{
371	if (!xfs_parent_sanity_check(ip->i_mount, parent_name, pptr)) {
372		ASSERT(0);
373		return -EFSCORRUPTED;
374	}
375
376	memset(scratch, 0, sizeof(struct xfs_da_args));
377	xfs_parent_da_args_init(scratch, NULL, pptr, ip, owner, parent_name);
378	return xfs_attr_set(scratch, XFS_ATTRUPDATE_REMOVE, false);
379}
~/ Read-only file preview.