Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (c) 2020-2022, Red Hat, Inc.
  4 * All Rights Reserved.
  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_mount.h"
 13#include "xfs_inode.h"
 14#include "xfs_trans.h"
 15#include "xfs_trans_priv.h"
 16#include "xfs_ag.h"
 17#include "xfs_iunlink_item.h"
 18#include "xfs_trace.h"
 19#include "xfs_error.h"
 20
 21struct kmem_cache	*xfs_iunlink_cache;
 22
 23static inline struct xfs_iunlink_item *IUL_ITEM(struct xfs_log_item *lip)
 24{
 25	return container_of(lip, struct xfs_iunlink_item, item);
 26}
 27
 28static void
 29xfs_iunlink_item_release(
 30	struct xfs_log_item	*lip)
 31{
 32	struct xfs_iunlink_item	*iup = IUL_ITEM(lip);
 33
 34	xfs_perag_put(iup->pag);
 35	kmem_cache_free(xfs_iunlink_cache, IUL_ITEM(lip));
 36}
 37
 38
 39static uint64_t
 40xfs_iunlink_item_sort(
 41	struct xfs_log_item	*lip)
 42{
 43	return IUL_ITEM(lip)->ip->i_ino;
 44}
 45
 46/*
 47 * Look up the inode cluster buffer and log the on-disk unlinked inode change
 48 * we need to make.
 49 */
 50static int
 51xfs_iunlink_log_dinode(
 52	struct xfs_trans	*tp,
 53	struct xfs_iunlink_item	*iup)
 54{
 55	struct xfs_inode	*ip = iup->ip;
 56	struct xfs_dinode	*dip;
 57	struct xfs_buf		*ibp;
 58	xfs_agino_t		old_ptr;
 59	int			offset;
 60	int			error;
 61
 62	error = xfs_imap_to_bp(tp->t_mountp, tp, &ip->i_imap, &ibp);
 63	if (error)
 64		return error;
 65	/*
 66	 * Don't log the unlinked field on stale buffers as this may be the
 67	 * transaction that frees the inode cluster and relogging the buffer
 68	 * here will incorrectly remove the stale state.
 69	 */
 70	if (ibp->b_flags & XBF_STALE)
 71		goto out;
 72
 73	dip = xfs_buf_offset(ibp, ip->i_imap.im_boffset);
 74
 75	/* Make sure the old pointer isn't garbage. */
 76	old_ptr = be32_to_cpu(dip->di_next_unlinked);
 77	if (old_ptr != iup->old_agino) {
 78		xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip,
 79				sizeof(*dip), __this_address);
 80		error = -EFSCORRUPTED;
 81		goto out;
 82	}
 83
 84	trace_xfs_iunlink_update_dinode(iup, old_ptr);
 85
 86	dip->di_next_unlinked = cpu_to_be32(iup->next_agino);
 87	offset = ip->i_imap.im_boffset +
 88			offsetof(struct xfs_dinode, di_next_unlinked);
 89
 90	xfs_dinode_calc_crc(tp->t_mountp, dip);
 91	xfs_trans_inode_buf(tp, ibp);
 92	xfs_trans_log_buf(tp, ibp, offset, offset + sizeof(xfs_agino_t) - 1);
 93	return 0;
 94out:
 95	xfs_trans_brelse(tp, ibp);
 96	return error;
 97}
 98
 99/*
100 * On precommit, we grab the inode cluster buffer for the inode number we were
101 * passed, then update the next unlinked field for that inode in the buffer and
102 * log the buffer. This ensures that the inode cluster buffer was logged in the
103 * correct order w.r.t. other inode cluster buffers. We can then remove the
104 * iunlink item from the transaction and release it as it is has now served it's
105 * purpose.
106 */
107static int
108xfs_iunlink_item_precommit(
109	struct xfs_trans	*tp,
110	struct xfs_log_item	*lip)
111{
112	struct xfs_iunlink_item	*iup = IUL_ITEM(lip);
113	int			error;
114
115	error = xfs_iunlink_log_dinode(tp, iup);
116	list_del(&lip->li_trans);
117	xfs_iunlink_item_release(lip);
118	return error;
119}
120
121static const struct xfs_item_ops xfs_iunlink_item_ops = {
122	.iop_release	= xfs_iunlink_item_release,
123	.iop_sort	= xfs_iunlink_item_sort,
124	.iop_precommit	= xfs_iunlink_item_precommit,
125};
126
127
128/*
129 * Initialize the inode log item for a newly allocated (in-core) inode.
130 *
131 * Inode extents can only reside within an AG. Hence specify the starting
132 * block for the inode chunk by offset within an AG as well as the
133 * length of the allocated extent.
134 *
135 * This joins the item to the transaction and marks it dirty so
136 * that we don't need a separate call to do this, nor does the
137 * caller need to know anything about the iunlink item.
138 */
139int
140xfs_iunlink_log_inode(
141	struct xfs_trans	*tp,
142	struct xfs_inode	*ip,
143	struct xfs_perag	*pag,
144	xfs_agino_t		next_agino)
145{
146	struct xfs_mount	*mp = tp->t_mountp;
147	struct xfs_iunlink_item	*iup;
148
149	ASSERT(xfs_verify_agino_or_null(pag, next_agino));
150	ASSERT(xfs_verify_agino_or_null(pag, ip->i_next_unlinked));
151
152	/*
153	 * Since we're updating a linked list, we should never find that the
154	 * current pointer is the same as the new value, unless we're
155	 * terminating the list.
156	 */
157	if (ip->i_next_unlinked == next_agino) {
158		if (next_agino != NULLAGINO)
159			return -EFSCORRUPTED;
160		return 0;
161	}
162
163	iup = kmem_cache_zalloc(xfs_iunlink_cache, GFP_KERNEL | __GFP_NOFAIL);
164	xfs_log_item_init(mp, &iup->item, XFS_LI_IUNLINK,
165			  &xfs_iunlink_item_ops);
166
167	iup->ip = ip;
168	iup->next_agino = next_agino;
169	iup->old_agino = ip->i_next_unlinked;
170	iup->pag = xfs_perag_hold(pag);
171
172	xfs_trans_add_item(tp, &iup->item);
173	tp->t_flags |= XFS_TRANS_DIRTY;
174	set_bit(XFS_LI_DIRTY, &iup->item.li_flags);
175	return 0;
176}
177