File Index
Files and directories
Sign in
FILE

xfs_metadir.c

File preview with syntax highlighting.

linux-6.19.14/fs/xfs/libxfs/xfs_metadir.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Copyright (c) 2018-2024 Oracle.  All Rights Reserved.
  4 * Author: Darrick J. Wong <djwong@kernel.org>
  5 */
  6#include "xfs.h"
  7#include "xfs_fs.h"
  8#include "xfs_shared.h"
  9#include "xfs_format.h"
 10#include "xfs_log_format.h"
 11#include "xfs_trans_resv.h"
 12#include "xfs_bit.h"
 13#include "xfs_sb.h"
 14#include "xfs_mount.h"
 15#include "xfs_defer.h"
 16#include "xfs_trans.h"
 17#include "xfs_metafile.h"
 18#include "xfs_metadir.h"
 19#include "xfs_trace.h"
 20#include "xfs_inode.h"
 21#include "xfs_quota.h"
 22#include "xfs_ialloc.h"
 23#include "xfs_bmap_btree.h"
 24#include "xfs_da_format.h"
 25#include "xfs_da_btree.h"
 26#include "xfs_trans_space.h"
 27#include "xfs_ag.h"
 28#include "xfs_dir2.h"
 29#include "xfs_dir2_priv.h"
 30#include "xfs_parent.h"
 31#include "xfs_health.h"
 32#include "xfs_errortag.h"
 33#include "xfs_error.h"
 34#include "xfs_btree.h"
 35#include "xfs_alloc.h"
 36
 37/*
 38 * Metadata Directory Tree
 39 * =======================
 40 *
 41 * These functions provide an abstraction layer for looking up, creating, and
 42 * deleting metadata inodes that live within a special metadata directory tree.
 43 *
 44 * This code does not manage the five existing metadata inodes: real time
 45 * bitmap & summary; and the user, group, and quotas.  All other metadata
 46 * inodes must use only the xfs_meta{dir,file}_* functions.
 47 *
 48 * Callers wishing to create or hardlink a metadata inode must create an
 49 * xfs_metadir_update structure, call the appropriate xfs_metadir* function,
 50 * and then call xfs_metadir_commit or xfs_metadir_cancel to commit or cancel
 51 * the update.  Files in the metadata directory tree currently cannot be
 52 * unlinked.
 53 *
 54 * When the metadir feature is enabled, all metadata inodes must have the
 55 * "metadata" inode flag set to prevent them from being exposed to the outside
 56 * world.
 57 *
 58 * Callers must take the ILOCK of any inode in the metadata directory tree to
 59 * synchronize access to that inode.  It is never necessary to take the IOLOCK
 60 * or the MMAPLOCK since metadata inodes must not be exposed to user space.
 61 */
 62
 63static inline void
 64xfs_metadir_set_xname(
 65	struct xfs_name		*xname,
 66	const char		*path,
 67	unsigned char		ftype)
 68{
 69	xname->name = (const unsigned char *)path;
 70	xname->len = strlen(path);
 71	xname->type = ftype;
 72}
 73
 74/*
 75 * Given a parent directory @dp and a metadata inode path component @xname,
 76 * Look up the inode number in the directory, returning it in @ino.
 77 * @xname.type must match the directory entry's ftype.
 78 *
 79 * Caller must hold ILOCK_EXCL.
 80 */
 81static inline int
 82xfs_metadir_lookup(
 83	struct xfs_trans	*tp,
 84	struct xfs_inode	*dp,
 85	struct xfs_name		*xname,
 86	xfs_ino_t		*ino)
 87{
 88	struct xfs_mount	*mp = dp->i_mount;
 89	struct xfs_da_args	args = {
 90		.trans		= tp,
 91		.dp		= dp,
 92		.geo		= mp->m_dir_geo,
 93		.name		= xname->name,
 94		.namelen	= xname->len,
 95		.hashval	= xfs_dir2_hashname(mp, xname),
 96		.whichfork	= XFS_DATA_FORK,
 97		.op_flags	= XFS_DA_OP_OKNOENT,
 98		.owner		= dp->i_ino,
 99	};
100	int			error;
101
102	if (!S_ISDIR(VFS_I(dp)->i_mode)) {
103		xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR);
104		return -EFSCORRUPTED;
105	}
106	if (xfs_is_shutdown(mp))
107		return -EIO;
108
109	error = xfs_dir_lookup_args(&args);
110	if (error)
111		return error;
112
113	if (!xfs_verify_ino(mp, args.inumber)) {
114		xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR);
115		return -EFSCORRUPTED;
116	}
117	if (xname->type != XFS_DIR3_FT_UNKNOWN && xname->type != args.filetype) {
118		xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR);
119		return -EFSCORRUPTED;
120	}
121
122	trace_xfs_metadir_lookup(dp, xname, args.inumber);
123	*ino = args.inumber;
124	return 0;
125}
126
127/*
128 * Look up and read a metadata inode from the metadata directory.  If the path
129 * component doesn't exist, return -ENOENT.
130 */
131int
132xfs_metadir_load(
133	struct xfs_trans	*tp,
134	struct xfs_inode	*dp,
135	const char		*path,
136	enum xfs_metafile_type	metafile_type,
137	struct xfs_inode	**ipp)
138{
139	struct xfs_name		xname;
140	xfs_ino_t		ino;
141	int			error;
142
143	xfs_metadir_set_xname(&xname, path, XFS_DIR3_FT_UNKNOWN);
144
145	xfs_ilock(dp, XFS_ILOCK_EXCL);
146	error = xfs_metadir_lookup(tp, dp, &xname, &ino);
147	xfs_iunlock(dp, XFS_ILOCK_EXCL);
148	if (error)
149		return error;
150	return xfs_trans_metafile_iget(tp, ino, metafile_type, ipp);
151}
152
153/*
154 * Unlock and release resources after committing (or cancelling) a metadata
155 * directory tree operation.  The caller retains its reference to @upd->ip
156 * and must release it explicitly.
157 */
158static inline void
159xfs_metadir_teardown(
160	struct xfs_metadir_update	*upd,
161	int				error)
162{
163	trace_xfs_metadir_teardown(upd, error);
164
165	if (upd->ppargs) {
166		xfs_parent_finish(upd->dp->i_mount, upd->ppargs);
167		upd->ppargs = NULL;
168	}
169
170	if (upd->ip) {
171		if (upd->ip_locked)
172			xfs_iunlock(upd->ip, XFS_ILOCK_EXCL);
173		upd->ip_locked = false;
174	}
175
176	if (upd->dp_locked)
177		xfs_iunlock(upd->dp, XFS_ILOCK_EXCL);
178	upd->dp_locked = false;
179}
180
181/*
182 * Begin the process of creating a metadata file by allocating transactions
183 * and taking whatever resources we're going to need.
184 */
185int
186xfs_metadir_start_create(
187	struct xfs_metadir_update	*upd)
188{
189	struct xfs_mount		*mp = upd->dp->i_mount;
190	int				error;
191
192	ASSERT(upd->dp != NULL);
193	ASSERT(upd->ip == NULL);
194	ASSERT(xfs_has_metadir(mp));
195	ASSERT(upd->metafile_type != XFS_METAFILE_UNKNOWN);
196
197	error = xfs_parent_start(mp, &upd->ppargs);
198	if (error)
199		return error;
200
201	/*
202	 * If we ever need the ability to create rt metadata files on a
203	 * pre-metadir filesystem, we'll need to dqattach the parent here.
204	 * Currently we assume that mkfs will create the files and quotacheck
205	 * will account for them.
206	 */
207
208	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_create,
209			xfs_create_space_res(mp, MAXNAMELEN), 0, 0, &upd->tp);
210	if (error)
211		goto out_teardown;
212
213	/*
214	 * Lock the parent directory if there is one.  We can't ijoin it to
215	 * the transaction until after the child file has been created.
216	 */
217	xfs_ilock(upd->dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
218	upd->dp_locked = true;
219
220	trace_xfs_metadir_start_create(upd);
221	return 0;
222out_teardown:
223	xfs_metadir_teardown(upd, error);
224	return error;
225}
226
227/*
228 * Create a metadata inode with the given @mode, and insert it into the
229 * metadata directory tree at the given @upd->path.  The path up to the final
230 * component must already exist.  The final path component must not exist.
231 *
232 * The new metadata inode will be attached to the update structure @upd->ip,
233 * with the ILOCK held until the caller releases it.
234 *
235 * NOTE: This function may return a new inode to the caller even if it returns
236 * a negative error code.  If an inode is passed back, the caller must finish
237 * setting up the inode before releasing it.
238 */
239int
240xfs_metadir_create(
241	struct xfs_metadir_update	*upd,
242	umode_t				mode)
243{
244	struct xfs_icreate_args		args = {
245		.pip			= upd->dp,
246		.mode			= mode,
247	};
248	struct xfs_name			xname;
249	struct xfs_dir_update		du = {
250		.dp			= upd->dp,
251		.name			= &xname,
252		.ppargs			= upd->ppargs,
253	};
254	struct xfs_mount		*mp = upd->dp->i_mount;
255	xfs_ino_t			ino;
256	unsigned int			resblks;
257	int				error;
258
259	xfs_assert_ilocked(upd->dp, XFS_ILOCK_EXCL);
260
261	/* Check that the name does not already exist in the directory. */
262	xfs_metadir_set_xname(&xname, upd->path, XFS_DIR3_FT_UNKNOWN);
263	error = xfs_metadir_lookup(upd->tp, upd->dp, &xname, &ino);
264	switch (error) {
265	case -ENOENT:
266		break;
267	case 0:
268		error = -EEXIST;
269		fallthrough;
270	default:
271		return error;
272	}
273
274	/*
275	 * A newly created regular or special file just has one directory
276	 * entry pointing to them, but a directory also the "." entry
277	 * pointing to itself.
278	 */
279	error = xfs_dialloc(&upd->tp, &args, &ino);
280	if (error)
281		return error;
282	error = xfs_icreate(upd->tp, ino, &args, &upd->ip);
283	if (error)
284		return error;
285	du.ip = upd->ip;
286	xfs_metafile_set_iflag(upd->tp, upd->ip, upd->metafile_type);
287	upd->ip_locked = true;
288
289	/*
290	 * Join the directory inode to the transaction.  We do not do it
291	 * earlier because xfs_dialloc rolls the transaction.
292	 */
293	xfs_trans_ijoin(upd->tp, upd->dp, 0);
294
295	/* Create the entry. */
296	if (S_ISDIR(args.mode))
297		resblks = xfs_mkdir_space_res(mp, xname.len);
298	else
299		resblks = xfs_create_space_res(mp, xname.len);
300	xname.type = xfs_mode_to_ftype(args.mode);
301
302	trace_xfs_metadir_try_create(upd);
303
304	error = xfs_dir_create_child(upd->tp, resblks, &du);
305	if (error)
306		return error;
307
308	/* Metadir files are not accounted to quota. */
309
310	trace_xfs_metadir_create(upd);
311
312	return 0;
313}
314
315#ifndef __KERNEL__
316/*
317 * Begin the process of linking a metadata file by allocating transactions
318 * and locking whatever resources we're going to need.
319 */
320int
321xfs_metadir_start_link(
322	struct xfs_metadir_update	*upd)
323{
324	struct xfs_mount		*mp = upd->dp->i_mount;
325	unsigned int			resblks;
326	int				nospace_error = 0;
327	int				error;
328
329	ASSERT(upd->dp != NULL);
330	ASSERT(upd->ip != NULL);
331	ASSERT(xfs_has_metadir(mp));
332
333	error = xfs_parent_start(mp, &upd->ppargs);
334	if (error)
335		return error;
336
337	resblks = xfs_link_space_res(mp, MAXNAMELEN);
338	error = xfs_trans_alloc_dir(upd->dp, &M_RES(mp)->tr_link, upd->ip,
339			&resblks, &upd->tp, &nospace_error);
340	if (error)
341		goto out_teardown;
342	if (!resblks) {
343		/* We don't allow reservationless updates. */
344		xfs_trans_cancel(upd->tp);
345		upd->tp = NULL;
346		xfs_iunlock(upd->dp, XFS_ILOCK_EXCL);
347		xfs_iunlock(upd->ip, XFS_ILOCK_EXCL);
348		error = nospace_error;
349		goto out_teardown;
350	}
351
352	upd->dp_locked = true;
353	upd->ip_locked = true;
354
355	trace_xfs_metadir_start_link(upd);
356	return 0;
357out_teardown:
358	xfs_metadir_teardown(upd, error);
359	return error;
360}
361
362/*
363 * Link the metadata directory given by @path to the inode @upd->ip.
364 * The path (up to the final component) must already exist, but the final
365 * component must not already exist.
366 */
367int
368xfs_metadir_link(
369	struct xfs_metadir_update	*upd)
370{
371	struct xfs_name			xname;
372	struct xfs_dir_update		du = {
373		.dp			= upd->dp,
374		.name			= &xname,
375		.ip			= upd->ip,
376		.ppargs			= upd->ppargs,
377	};
378	struct xfs_mount		*mp = upd->dp->i_mount;
379	xfs_ino_t			ino;
380	unsigned int			resblks;
381	int				error;
382
383	xfs_assert_ilocked(upd->dp, XFS_ILOCK_EXCL);
384	xfs_assert_ilocked(upd->ip, XFS_ILOCK_EXCL);
385
386	/* Look up the name in the current directory. */
387	xfs_metadir_set_xname(&xname, upd->path,
388			xfs_mode_to_ftype(VFS_I(upd->ip)->i_mode));
389	error = xfs_metadir_lookup(upd->tp, upd->dp, &xname, &ino);
390	switch (error) {
391	case -ENOENT:
392		break;
393	case 0:
394		error = -EEXIST;
395		fallthrough;
396	default:
397		return error;
398	}
399
400	resblks = xfs_link_space_res(mp, xname.len);
401	error = xfs_dir_add_child(upd->tp, resblks, &du);
402	if (error)
403		return error;
404
405	trace_xfs_metadir_link(upd);
406
407	return 0;
408}
409#endif /* ! __KERNEL__ */
410
411/* Commit a metadir update and unlock/drop all resources. */
412int
413xfs_metadir_commit(
414	struct xfs_metadir_update	*upd)
415{
416	int				error;
417
418	trace_xfs_metadir_commit(upd);
419
420	error = xfs_trans_commit(upd->tp);
421	upd->tp = NULL;
422
423	xfs_metadir_teardown(upd, error);
424	return error;
425}
426
427/* Cancel a metadir update and unlock/drop all resources. */
428void
429xfs_metadir_cancel(
430	struct xfs_metadir_update	*upd,
431	int				error)
432{
433	trace_xfs_metadir_cancel(upd);
434
435	xfs_trans_cancel(upd->tp);
436	upd->tp = NULL;
437
438	xfs_metadir_teardown(upd, error);
439}
440
441/* Create a metadata for the last component of the path. */
442int
443xfs_metadir_mkdir(
444	struct xfs_inode		*dp,
445	const char			*path,
446	struct xfs_inode		**ipp)
447{
448	struct xfs_metadir_update	upd = {
449		.dp			= dp,
450		.path			= path,
451		.metafile_type		= XFS_METAFILE_DIR,
452	};
453	int				error;
454
455	if (xfs_is_shutdown(dp->i_mount))
456		return -EIO;
457
458	/* Allocate a transaction to create the last directory. */
459	error = xfs_metadir_start_create(&upd);
460	if (error)
461		return error;
462
463	/* Create the subdirectory and take our reference. */
464	error = xfs_metadir_create(&upd, S_IFDIR);
465	if (error)
466		goto out_cancel;
467
468	error = xfs_metadir_commit(&upd);
469	if (error)
470		goto out_irele;
471
472	xfs_finish_inode_setup(upd.ip);
473	*ipp = upd.ip;
474	return 0;
475
476out_cancel:
477	xfs_metadir_cancel(&upd, error);
478out_irele:
479	/* Have to finish setting up the inode to ensure it's deleted. */
480	if (upd.ip) {
481		xfs_finish_inode_setup(upd.ip);
482		xfs_irele(upd.ip);
483	}
484	return error;
485}
~/ Read-only file preview.