Linux Audio

Check our new training course

Loading...
v4.17
  1/*
  2 * Copyright (C) 2016 Oracle.  All Rights Reserved.
  3 *
  4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
  5 *
  6 * This program is free software; you can redistribute it and/or
  7 * modify it under the terms of the GNU General Public License
  8 * as published by the Free Software Foundation; either version 2
  9 * of the License, or (at your option) any later version.
 10 *
 11 * This program is distributed in the hope that it would be useful,
 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14 * GNU General Public License for more details.
 15 *
 16 * You should have received a copy of the GNU General Public License
 17 * along with this program; if not, write the Free Software Foundation,
 18 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
 19 */
 20#include "xfs.h"
 21#include "xfs_fs.h"
 22#include "xfs_shared.h"
 23#include "xfs_format.h"
 24#include "xfs_log_format.h"
 25#include "xfs_trans_resv.h"
 26#include "xfs_mount.h"
 27#include "xfs_defer.h"
 28#include "xfs_trans.h"
 29#include "xfs_trans_priv.h"
 30#include "xfs_bmap_item.h"
 31#include "xfs_alloc.h"
 32#include "xfs_bmap.h"
 33#include "xfs_inode.h"
 34
 35/*
 36 * This routine is called to allocate a "bmap update done"
 37 * log item.
 38 */
 39struct xfs_bud_log_item *
 40xfs_trans_get_bud(
 41	struct xfs_trans		*tp,
 42	struct xfs_bui_log_item		*buip)
 43{
 44	struct xfs_bud_log_item		*budp;
 45
 46	budp = xfs_bud_init(tp->t_mountp, buip);
 47	xfs_trans_add_item(tp, &budp->bud_item);
 48	return budp;
 49}
 50
 51/*
 52 * Finish an bmap update and log it to the BUD. Note that the
 53 * transaction is marked dirty regardless of whether the bmap update
 54 * succeeds or fails to support the BUI/BUD lifecycle rules.
 55 */
 56int
 57xfs_trans_log_finish_bmap_update(
 58	struct xfs_trans		*tp,
 59	struct xfs_bud_log_item		*budp,
 60	struct xfs_defer_ops		*dop,
 61	enum xfs_bmap_intent_type	type,
 62	struct xfs_inode		*ip,
 63	int				whichfork,
 64	xfs_fileoff_t			startoff,
 65	xfs_fsblock_t			startblock,
 66	xfs_filblks_t			*blockcount,
 67	xfs_exntst_t			state)
 68{
 69	int				error;
 70
 71	error = xfs_bmap_finish_one(tp, dop, ip, type, whichfork, startoff,
 72			startblock, blockcount, state);
 73
 74	/*
 75	 * Mark the transaction dirty, even on error. This ensures the
 76	 * transaction is aborted, which:
 77	 *
 78	 * 1.) releases the BUI and frees the BUD
 79	 * 2.) shuts down the filesystem
 80	 */
 81	tp->t_flags |= XFS_TRANS_DIRTY;
 82	budp->bud_item.li_desc->lid_flags |= XFS_LID_DIRTY;
 83
 84	return error;
 85}
 86
 87/* Sort bmap intents by inode. */
 88static int
 89xfs_bmap_update_diff_items(
 90	void				*priv,
 91	struct list_head		*a,
 92	struct list_head		*b)
 93{
 94	struct xfs_bmap_intent		*ba;
 95	struct xfs_bmap_intent		*bb;
 96
 97	ba = container_of(a, struct xfs_bmap_intent, bi_list);
 98	bb = container_of(b, struct xfs_bmap_intent, bi_list);
 99	return ba->bi_owner->i_ino - bb->bi_owner->i_ino;
100}
101
102/* Get an BUI. */
103STATIC void *
104xfs_bmap_update_create_intent(
105	struct xfs_trans		*tp,
106	unsigned int			count)
107{
108	struct xfs_bui_log_item		*buip;
109
110	ASSERT(count == XFS_BUI_MAX_FAST_EXTENTS);
111	ASSERT(tp != NULL);
112
113	buip = xfs_bui_init(tp->t_mountp);
114	ASSERT(buip != NULL);
115
116	/*
117	 * Get a log_item_desc to point at the new item.
118	 */
119	xfs_trans_add_item(tp, &buip->bui_item);
120	return buip;
121}
122
123/* Set the map extent flags for this mapping. */
124static void
125xfs_trans_set_bmap_flags(
126	struct xfs_map_extent		*bmap,
127	enum xfs_bmap_intent_type	type,
128	int				whichfork,
129	xfs_exntst_t			state)
130{
131	bmap->me_flags = 0;
132	switch (type) {
133	case XFS_BMAP_MAP:
134	case XFS_BMAP_UNMAP:
135		bmap->me_flags = type;
136		break;
137	default:
138		ASSERT(0);
139	}
140	if (state == XFS_EXT_UNWRITTEN)
141		bmap->me_flags |= XFS_BMAP_EXTENT_UNWRITTEN;
142	if (whichfork == XFS_ATTR_FORK)
143		bmap->me_flags |= XFS_BMAP_EXTENT_ATTR_FORK;
144}
145
146/* Log bmap updates in the intent item. */
147STATIC void
148xfs_bmap_update_log_item(
149	struct xfs_trans		*tp,
150	void				*intent,
151	struct list_head		*item)
152{
153	struct xfs_bui_log_item		*buip = intent;
154	struct xfs_bmap_intent		*bmap;
155	uint				next_extent;
156	struct xfs_map_extent		*map;
157
158	bmap = container_of(item, struct xfs_bmap_intent, bi_list);
159
160	tp->t_flags |= XFS_TRANS_DIRTY;
161	buip->bui_item.li_desc->lid_flags |= XFS_LID_DIRTY;
162
163	/*
164	 * atomic_inc_return gives us the value after the increment;
165	 * we want to use it as an array index so we need to subtract 1 from
166	 * it.
167	 */
168	next_extent = atomic_inc_return(&buip->bui_next_extent) - 1;
169	ASSERT(next_extent < buip->bui_format.bui_nextents);
170	map = &buip->bui_format.bui_extents[next_extent];
171	map->me_owner = bmap->bi_owner->i_ino;
172	map->me_startblock = bmap->bi_bmap.br_startblock;
173	map->me_startoff = bmap->bi_bmap.br_startoff;
174	map->me_len = bmap->bi_bmap.br_blockcount;
175	xfs_trans_set_bmap_flags(map, bmap->bi_type, bmap->bi_whichfork,
176			bmap->bi_bmap.br_state);
177}
178
179/* Get an BUD so we can process all the deferred rmap updates. */
180STATIC void *
181xfs_bmap_update_create_done(
182	struct xfs_trans		*tp,
183	void				*intent,
184	unsigned int			count)
185{
186	return xfs_trans_get_bud(tp, intent);
187}
188
189/* Process a deferred rmap update. */
190STATIC int
191xfs_bmap_update_finish_item(
192	struct xfs_trans		*tp,
193	struct xfs_defer_ops		*dop,
194	struct list_head		*item,
195	void				*done_item,
196	void				**state)
197{
198	struct xfs_bmap_intent		*bmap;
199	xfs_filblks_t			count;
200	int				error;
201
202	bmap = container_of(item, struct xfs_bmap_intent, bi_list);
203	count = bmap->bi_bmap.br_blockcount;
204	error = xfs_trans_log_finish_bmap_update(tp, done_item, dop,
205			bmap->bi_type,
206			bmap->bi_owner, bmap->bi_whichfork,
207			bmap->bi_bmap.br_startoff,
208			bmap->bi_bmap.br_startblock,
209			&count,
210			bmap->bi_bmap.br_state);
211	if (!error && count > 0) {
212		ASSERT(bmap->bi_type == XFS_BMAP_UNMAP);
213		bmap->bi_bmap.br_blockcount = count;
214		return -EAGAIN;
215	}
216	kmem_free(bmap);
217	return error;
218}
219
220/* Abort all pending BUIs. */
221STATIC void
222xfs_bmap_update_abort_intent(
223	void				*intent)
224{
225	xfs_bui_release(intent);
226}
227
228/* Cancel a deferred rmap update. */
229STATIC void
230xfs_bmap_update_cancel_item(
231	struct list_head		*item)
232{
233	struct xfs_bmap_intent		*bmap;
234
235	bmap = container_of(item, struct xfs_bmap_intent, bi_list);
236	kmem_free(bmap);
237}
238
239static const struct xfs_defer_op_type xfs_bmap_update_defer_type = {
240	.type		= XFS_DEFER_OPS_TYPE_BMAP,
241	.max_items	= XFS_BUI_MAX_FAST_EXTENTS,
242	.diff_items	= xfs_bmap_update_diff_items,
243	.create_intent	= xfs_bmap_update_create_intent,
244	.abort_intent	= xfs_bmap_update_abort_intent,
245	.log_item	= xfs_bmap_update_log_item,
246	.create_done	= xfs_bmap_update_create_done,
247	.finish_item	= xfs_bmap_update_finish_item,
248	.cancel_item	= xfs_bmap_update_cancel_item,
249};
250
251/* Register the deferred op type. */
252void
253xfs_bmap_update_init_defer_op(void)
254{
255	xfs_defer_init_op_type(&xfs_bmap_update_defer_type);
256}
v4.10.11
  1/*
  2 * Copyright (C) 2016 Oracle.  All Rights Reserved.
  3 *
  4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
  5 *
  6 * This program is free software; you can redistribute it and/or
  7 * modify it under the terms of the GNU General Public License
  8 * as published by the Free Software Foundation; either version 2
  9 * of the License, or (at your option) any later version.
 10 *
 11 * This program is distributed in the hope that it would be useful,
 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14 * GNU General Public License for more details.
 15 *
 16 * You should have received a copy of the GNU General Public License
 17 * along with this program; if not, write the Free Software Foundation,
 18 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
 19 */
 20#include "xfs.h"
 21#include "xfs_fs.h"
 22#include "xfs_shared.h"
 23#include "xfs_format.h"
 24#include "xfs_log_format.h"
 25#include "xfs_trans_resv.h"
 26#include "xfs_mount.h"
 27#include "xfs_defer.h"
 28#include "xfs_trans.h"
 29#include "xfs_trans_priv.h"
 30#include "xfs_bmap_item.h"
 31#include "xfs_alloc.h"
 32#include "xfs_bmap.h"
 33#include "xfs_inode.h"
 34
 35/*
 36 * This routine is called to allocate a "bmap update done"
 37 * log item.
 38 */
 39struct xfs_bud_log_item *
 40xfs_trans_get_bud(
 41	struct xfs_trans		*tp,
 42	struct xfs_bui_log_item		*buip)
 43{
 44	struct xfs_bud_log_item		*budp;
 45
 46	budp = xfs_bud_init(tp->t_mountp, buip);
 47	xfs_trans_add_item(tp, &budp->bud_item);
 48	return budp;
 49}
 50
 51/*
 52 * Finish an bmap update and log it to the BUD. Note that the
 53 * transaction is marked dirty regardless of whether the bmap update
 54 * succeeds or fails to support the BUI/BUD lifecycle rules.
 55 */
 56int
 57xfs_trans_log_finish_bmap_update(
 58	struct xfs_trans		*tp,
 59	struct xfs_bud_log_item		*budp,
 60	struct xfs_defer_ops		*dop,
 61	enum xfs_bmap_intent_type	type,
 62	struct xfs_inode		*ip,
 63	int				whichfork,
 64	xfs_fileoff_t			startoff,
 65	xfs_fsblock_t			startblock,
 66	xfs_filblks_t			blockcount,
 67	xfs_exntst_t			state)
 68{
 69	int				error;
 70
 71	error = xfs_bmap_finish_one(tp, dop, ip, type, whichfork, startoff,
 72			startblock, blockcount, state);
 73
 74	/*
 75	 * Mark the transaction dirty, even on error. This ensures the
 76	 * transaction is aborted, which:
 77	 *
 78	 * 1.) releases the BUI and frees the BUD
 79	 * 2.) shuts down the filesystem
 80	 */
 81	tp->t_flags |= XFS_TRANS_DIRTY;
 82	budp->bud_item.li_desc->lid_flags |= XFS_LID_DIRTY;
 83
 84	return error;
 85}
 86
 87/* Sort bmap intents by inode. */
 88static int
 89xfs_bmap_update_diff_items(
 90	void				*priv,
 91	struct list_head		*a,
 92	struct list_head		*b)
 93{
 94	struct xfs_bmap_intent		*ba;
 95	struct xfs_bmap_intent		*bb;
 96
 97	ba = container_of(a, struct xfs_bmap_intent, bi_list);
 98	bb = container_of(b, struct xfs_bmap_intent, bi_list);
 99	return ba->bi_owner->i_ino - bb->bi_owner->i_ino;
100}
101
102/* Get an BUI. */
103STATIC void *
104xfs_bmap_update_create_intent(
105	struct xfs_trans		*tp,
106	unsigned int			count)
107{
108	struct xfs_bui_log_item		*buip;
109
110	ASSERT(count == XFS_BUI_MAX_FAST_EXTENTS);
111	ASSERT(tp != NULL);
112
113	buip = xfs_bui_init(tp->t_mountp);
114	ASSERT(buip != NULL);
115
116	/*
117	 * Get a log_item_desc to point at the new item.
118	 */
119	xfs_trans_add_item(tp, &buip->bui_item);
120	return buip;
121}
122
123/* Set the map extent flags for this mapping. */
124static void
125xfs_trans_set_bmap_flags(
126	struct xfs_map_extent		*bmap,
127	enum xfs_bmap_intent_type	type,
128	int				whichfork,
129	xfs_exntst_t			state)
130{
131	bmap->me_flags = 0;
132	switch (type) {
133	case XFS_BMAP_MAP:
134	case XFS_BMAP_UNMAP:
135		bmap->me_flags = type;
136		break;
137	default:
138		ASSERT(0);
139	}
140	if (state == XFS_EXT_UNWRITTEN)
141		bmap->me_flags |= XFS_BMAP_EXTENT_UNWRITTEN;
142	if (whichfork == XFS_ATTR_FORK)
143		bmap->me_flags |= XFS_BMAP_EXTENT_ATTR_FORK;
144}
145
146/* Log bmap updates in the intent item. */
147STATIC void
148xfs_bmap_update_log_item(
149	struct xfs_trans		*tp,
150	void				*intent,
151	struct list_head		*item)
152{
153	struct xfs_bui_log_item		*buip = intent;
154	struct xfs_bmap_intent		*bmap;
155	uint				next_extent;
156	struct xfs_map_extent		*map;
157
158	bmap = container_of(item, struct xfs_bmap_intent, bi_list);
159
160	tp->t_flags |= XFS_TRANS_DIRTY;
161	buip->bui_item.li_desc->lid_flags |= XFS_LID_DIRTY;
162
163	/*
164	 * atomic_inc_return gives us the value after the increment;
165	 * we want to use it as an array index so we need to subtract 1 from
166	 * it.
167	 */
168	next_extent = atomic_inc_return(&buip->bui_next_extent) - 1;
169	ASSERT(next_extent < buip->bui_format.bui_nextents);
170	map = &buip->bui_format.bui_extents[next_extent];
171	map->me_owner = bmap->bi_owner->i_ino;
172	map->me_startblock = bmap->bi_bmap.br_startblock;
173	map->me_startoff = bmap->bi_bmap.br_startoff;
174	map->me_len = bmap->bi_bmap.br_blockcount;
175	xfs_trans_set_bmap_flags(map, bmap->bi_type, bmap->bi_whichfork,
176			bmap->bi_bmap.br_state);
177}
178
179/* Get an BUD so we can process all the deferred rmap updates. */
180STATIC void *
181xfs_bmap_update_create_done(
182	struct xfs_trans		*tp,
183	void				*intent,
184	unsigned int			count)
185{
186	return xfs_trans_get_bud(tp, intent);
187}
188
189/* Process a deferred rmap update. */
190STATIC int
191xfs_bmap_update_finish_item(
192	struct xfs_trans		*tp,
193	struct xfs_defer_ops		*dop,
194	struct list_head		*item,
195	void				*done_item,
196	void				**state)
197{
198	struct xfs_bmap_intent		*bmap;
 
199	int				error;
200
201	bmap = container_of(item, struct xfs_bmap_intent, bi_list);
 
202	error = xfs_trans_log_finish_bmap_update(tp, done_item, dop,
203			bmap->bi_type,
204			bmap->bi_owner, bmap->bi_whichfork,
205			bmap->bi_bmap.br_startoff,
206			bmap->bi_bmap.br_startblock,
207			bmap->bi_bmap.br_blockcount,
208			bmap->bi_bmap.br_state);
 
 
 
 
 
209	kmem_free(bmap);
210	return error;
211}
212
213/* Abort all pending BUIs. */
214STATIC void
215xfs_bmap_update_abort_intent(
216	void				*intent)
217{
218	xfs_bui_release(intent);
219}
220
221/* Cancel a deferred rmap update. */
222STATIC void
223xfs_bmap_update_cancel_item(
224	struct list_head		*item)
225{
226	struct xfs_bmap_intent		*bmap;
227
228	bmap = container_of(item, struct xfs_bmap_intent, bi_list);
229	kmem_free(bmap);
230}
231
232static const struct xfs_defer_op_type xfs_bmap_update_defer_type = {
233	.type		= XFS_DEFER_OPS_TYPE_BMAP,
234	.max_items	= XFS_BUI_MAX_FAST_EXTENTS,
235	.diff_items	= xfs_bmap_update_diff_items,
236	.create_intent	= xfs_bmap_update_create_intent,
237	.abort_intent	= xfs_bmap_update_abort_intent,
238	.log_item	= xfs_bmap_update_log_item,
239	.create_done	= xfs_bmap_update_create_done,
240	.finish_item	= xfs_bmap_update_finish_item,
241	.cancel_item	= xfs_bmap_update_cancel_item,
242};
243
244/* Register the deferred op type. */
245void
246xfs_bmap_update_init_defer_op(void)
247{
248	xfs_defer_init_op_type(&xfs_bmap_update_defer_type);
249}