1 |
1275 |
phoenix |
/*
|
2 |
|
|
* Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
|
3 |
|
|
*
|
4 |
|
|
* This program is free software; you can redistribute it and/or modify it
|
5 |
|
|
* under the terms of version 2 of the GNU General Public License as
|
6 |
|
|
* published by the Free Software Foundation.
|
7 |
|
|
*
|
8 |
|
|
* This program is distributed in the hope that it would be useful, but
|
9 |
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
10 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
11 |
|
|
*
|
12 |
|
|
* Further, this software is distributed without any warranty that it is
|
13 |
|
|
* free of the rightful claim of any third person regarding infringement
|
14 |
|
|
* or the like. Any license provided herein, whether implied or
|
15 |
|
|
* otherwise, applies only to this software file. Patent licenses, if
|
16 |
|
|
* any, provided herein do not apply to combinations of this program with
|
17 |
|
|
* other software, or any other product whatsoever.
|
18 |
|
|
*
|
19 |
|
|
* You should have received a copy of the GNU General Public License along
|
20 |
|
|
* with this program; if not, write the Free Software Foundation, Inc., 59
|
21 |
|
|
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
22 |
|
|
*
|
23 |
|
|
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
|
24 |
|
|
* Mountain View, CA 94043, or:
|
25 |
|
|
*
|
26 |
|
|
* http://www.sgi.com
|
27 |
|
|
*
|
28 |
|
|
* For further information regarding this notice, see:
|
29 |
|
|
*
|
30 |
|
|
* http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
|
31 |
|
|
*/
|
32 |
|
|
|
33 |
|
|
#include "xfs.h"
|
34 |
|
|
#include "xfs_macros.h"
|
35 |
|
|
#include "xfs_types.h"
|
36 |
|
|
#include "xfs_inum.h"
|
37 |
|
|
#include "xfs_log.h"
|
38 |
|
|
#include "xfs_trans.h"
|
39 |
|
|
#include "xfs_sb.h"
|
40 |
|
|
#include "xfs_ag.h"
|
41 |
|
|
#include "xfs_dir.h"
|
42 |
|
|
#include "xfs_dir2.h"
|
43 |
|
|
#include "xfs_dmapi.h"
|
44 |
|
|
#include "xfs_mount.h"
|
45 |
|
|
#include "xfs_error.h"
|
46 |
|
|
#include "xfs_trans_priv.h"
|
47 |
|
|
#include "xfs_alloc_btree.h"
|
48 |
|
|
#include "xfs_bmap_btree.h"
|
49 |
|
|
#include "xfs_ialloc_btree.h"
|
50 |
|
|
#include "xfs_btree.h"
|
51 |
|
|
#include "xfs_ialloc.h"
|
52 |
|
|
#include "xfs_alloc.h"
|
53 |
|
|
#include "xfs_attr_sf.h"
|
54 |
|
|
#include "xfs_dir_sf.h"
|
55 |
|
|
#include "xfs_dir2_sf.h"
|
56 |
|
|
#include "xfs_dinode.h"
|
57 |
|
|
#include "xfs_inode.h"
|
58 |
|
|
#include "xfs_bmap.h"
|
59 |
|
|
#include "xfs_da_btree.h"
|
60 |
|
|
#include "xfs_quota.h"
|
61 |
|
|
#include "xfs_trans_space.h"
|
62 |
|
|
|
63 |
|
|
|
64 |
|
|
STATIC void xfs_trans_apply_sb_deltas(xfs_trans_t *);
|
65 |
|
|
STATIC uint xfs_trans_count_vecs(xfs_trans_t *);
|
66 |
|
|
STATIC void xfs_trans_fill_vecs(xfs_trans_t *, xfs_log_iovec_t *);
|
67 |
|
|
STATIC void xfs_trans_uncommit(xfs_trans_t *, uint);
|
68 |
|
|
STATIC void xfs_trans_committed(xfs_trans_t *, int);
|
69 |
|
|
STATIC void xfs_trans_chunk_committed(xfs_log_item_chunk_t *, xfs_lsn_t, int);
|
70 |
|
|
STATIC void xfs_trans_free(xfs_trans_t *);
|
71 |
|
|
|
72 |
|
|
kmem_zone_t *xfs_trans_zone;
|
73 |
|
|
|
74 |
|
|
|
75 |
|
|
/*
|
76 |
|
|
* Initialize the precomputed transaction reservation values
|
77 |
|
|
* in the mount structure.
|
78 |
|
|
*/
|
79 |
|
|
void
|
80 |
|
|
xfs_trans_init(
|
81 |
|
|
xfs_mount_t *mp)
|
82 |
|
|
{
|
83 |
|
|
xfs_trans_reservations_t *resp;
|
84 |
|
|
|
85 |
|
|
resp = &(mp->m_reservations);
|
86 |
|
|
resp->tr_write =
|
87 |
|
|
(uint)(XFS_CALC_WRITE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));
|
88 |
|
|
resp->tr_itruncate =
|
89 |
|
|
(uint)(XFS_CALC_ITRUNCATE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));
|
90 |
|
|
resp->tr_rename =
|
91 |
|
|
(uint)(XFS_CALC_RENAME_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));
|
92 |
|
|
resp->tr_link = (uint)XFS_CALC_LINK_LOG_RES(mp);
|
93 |
|
|
resp->tr_remove =
|
94 |
|
|
(uint)(XFS_CALC_REMOVE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));
|
95 |
|
|
resp->tr_symlink =
|
96 |
|
|
(uint)(XFS_CALC_SYMLINK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));
|
97 |
|
|
resp->tr_create =
|
98 |
|
|
(uint)(XFS_CALC_CREATE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));
|
99 |
|
|
resp->tr_mkdir =
|
100 |
|
|
(uint)(XFS_CALC_MKDIR_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));
|
101 |
|
|
resp->tr_ifree =
|
102 |
|
|
(uint)(XFS_CALC_IFREE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));
|
103 |
|
|
resp->tr_ichange =
|
104 |
|
|
(uint)(XFS_CALC_ICHANGE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));
|
105 |
|
|
resp->tr_growdata = (uint)XFS_CALC_GROWDATA_LOG_RES(mp);
|
106 |
|
|
resp->tr_swrite = (uint)XFS_CALC_SWRITE_LOG_RES(mp);
|
107 |
|
|
resp->tr_writeid = (uint)XFS_CALC_WRITEID_LOG_RES(mp);
|
108 |
|
|
resp->tr_addafork =
|
109 |
|
|
(uint)(XFS_CALC_ADDAFORK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));
|
110 |
|
|
resp->tr_attrinval = (uint)XFS_CALC_ATTRINVAL_LOG_RES(mp);
|
111 |
|
|
resp->tr_attrset =
|
112 |
|
|
(uint)(XFS_CALC_ATTRSET_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));
|
113 |
|
|
resp->tr_attrrm =
|
114 |
|
|
(uint)(XFS_CALC_ATTRRM_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp));
|
115 |
|
|
resp->tr_clearagi = (uint)XFS_CALC_CLEAR_AGI_BUCKET_LOG_RES(mp);
|
116 |
|
|
resp->tr_growrtalloc = (uint)XFS_CALC_GROWRTALLOC_LOG_RES(mp);
|
117 |
|
|
resp->tr_growrtzero = (uint)XFS_CALC_GROWRTZERO_LOG_RES(mp);
|
118 |
|
|
resp->tr_growrtfree = (uint)XFS_CALC_GROWRTFREE_LOG_RES(mp);
|
119 |
|
|
}
|
120 |
|
|
|
121 |
|
|
/*
|
122 |
|
|
* This routine is called to allocate a transaction structure.
|
123 |
|
|
* The type parameter indicates the type of the transaction. These
|
124 |
|
|
* are enumerated in xfs_trans.h.
|
125 |
|
|
*
|
126 |
|
|
* Dynamically allocate the transaction structure from the transaction
|
127 |
|
|
* zone, initialize it, and return it to the caller.
|
128 |
|
|
*/
|
129 |
|
|
xfs_trans_t *
|
130 |
|
|
xfs_trans_alloc(
|
131 |
|
|
xfs_mount_t *mp,
|
132 |
|
|
uint type)
|
133 |
|
|
{
|
134 |
|
|
xfs_check_frozen(mp, NULL, XFS_FREEZE_TRANS);
|
135 |
|
|
return (_xfs_trans_alloc(mp, type));
|
136 |
|
|
|
137 |
|
|
}
|
138 |
|
|
|
139 |
|
|
xfs_trans_t *
|
140 |
|
|
_xfs_trans_alloc(
|
141 |
|
|
xfs_mount_t *mp,
|
142 |
|
|
uint type)
|
143 |
|
|
{
|
144 |
|
|
xfs_trans_t *tp;
|
145 |
|
|
|
146 |
|
|
ASSERT(xfs_trans_zone != NULL);
|
147 |
|
|
tp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP);
|
148 |
|
|
|
149 |
|
|
/*
|
150 |
|
|
* Initialize the transaction structure.
|
151 |
|
|
*/
|
152 |
|
|
tp->t_magic = XFS_TRANS_MAGIC;
|
153 |
|
|
tp->t_type = type;
|
154 |
|
|
tp->t_mountp = mp;
|
155 |
|
|
tp->t_items_free = XFS_LIC_NUM_SLOTS;
|
156 |
|
|
tp->t_busy_free = XFS_LBC_NUM_SLOTS;
|
157 |
|
|
XFS_LIC_INIT(&(tp->t_items));
|
158 |
|
|
XFS_LBC_INIT(&(tp->t_busy));
|
159 |
|
|
|
160 |
|
|
return (tp);
|
161 |
|
|
}
|
162 |
|
|
|
163 |
|
|
/*
|
164 |
|
|
* This is called to create a new transaction which will share the
|
165 |
|
|
* permanent log reservation of the given transaction. The remaining
|
166 |
|
|
* unused block and rt extent reservations are also inherited. This
|
167 |
|
|
* implies that the original transaction is no longer allowed to allocate
|
168 |
|
|
* blocks. Locks and log items, however, are no inherited. They must
|
169 |
|
|
* be added to the new transaction explicitly.
|
170 |
|
|
*/
|
171 |
|
|
xfs_trans_t *
|
172 |
|
|
xfs_trans_dup(
|
173 |
|
|
xfs_trans_t *tp)
|
174 |
|
|
{
|
175 |
|
|
xfs_trans_t *ntp;
|
176 |
|
|
|
177 |
|
|
ntp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP);
|
178 |
|
|
|
179 |
|
|
/*
|
180 |
|
|
* Initialize the new transaction structure.
|
181 |
|
|
*/
|
182 |
|
|
ntp->t_magic = XFS_TRANS_MAGIC;
|
183 |
|
|
ntp->t_type = tp->t_type;
|
184 |
|
|
ntp->t_mountp = tp->t_mountp;
|
185 |
|
|
ntp->t_items_free = XFS_LIC_NUM_SLOTS;
|
186 |
|
|
ntp->t_busy_free = XFS_LBC_NUM_SLOTS;
|
187 |
|
|
XFS_LIC_INIT(&(ntp->t_items));
|
188 |
|
|
XFS_LBC_INIT(&(ntp->t_busy));
|
189 |
|
|
|
190 |
|
|
ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
|
191 |
|
|
|
192 |
|
|
#if defined(XLOG_NOLOG) || defined(DEBUG)
|
193 |
|
|
ASSERT(!xlog_debug || tp->t_ticket != NULL);
|
194 |
|
|
#else
|
195 |
|
|
ASSERT(tp->t_ticket != NULL);
|
196 |
|
|
#endif
|
197 |
|
|
ntp->t_flags = XFS_TRANS_PERM_LOG_RES | (tp->t_flags & XFS_TRANS_RESERVE);
|
198 |
|
|
ntp->t_ticket = tp->t_ticket;
|
199 |
|
|
ntp->t_blk_res = tp->t_blk_res - tp->t_blk_res_used;
|
200 |
|
|
tp->t_blk_res = tp->t_blk_res_used;
|
201 |
|
|
ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used;
|
202 |
|
|
tp->t_rtx_res = tp->t_rtx_res_used;
|
203 |
|
|
PFLAGS_DUP(&tp->t_pflags, &ntp->t_pflags);
|
204 |
|
|
|
205 |
|
|
XFS_TRANS_DUP_DQINFO(tp->t_mountp, tp, ntp);
|
206 |
|
|
|
207 |
|
|
atomic_inc(&tp->t_mountp->m_active_trans);
|
208 |
|
|
return ntp;
|
209 |
|
|
}
|
210 |
|
|
|
211 |
|
|
/*
|
212 |
|
|
* This is called to reserve free disk blocks and log space for the
|
213 |
|
|
* given transaction. This must be done before allocating any resources
|
214 |
|
|
* within the transaction.
|
215 |
|
|
*
|
216 |
|
|
* This will return ENOSPC if there are not enough blocks available.
|
217 |
|
|
* It will sleep waiting for available log space.
|
218 |
|
|
* The only valid value for the flags parameter is XFS_RES_LOG_PERM, which
|
219 |
|
|
* is used by long running transactions. If any one of the reservations
|
220 |
|
|
* fails then they will all be backed out.
|
221 |
|
|
*
|
222 |
|
|
* This does not do quota reservations. That typically is done by the
|
223 |
|
|
* caller afterwards.
|
224 |
|
|
*/
|
225 |
|
|
int
|
226 |
|
|
xfs_trans_reserve(
|
227 |
|
|
xfs_trans_t *tp,
|
228 |
|
|
uint blocks,
|
229 |
|
|
uint logspace,
|
230 |
|
|
uint rtextents,
|
231 |
|
|
uint flags,
|
232 |
|
|
uint logcount)
|
233 |
|
|
{
|
234 |
|
|
int log_flags;
|
235 |
|
|
int error;
|
236 |
|
|
int rsvd;
|
237 |
|
|
|
238 |
|
|
error = 0;
|
239 |
|
|
rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
|
240 |
|
|
|
241 |
|
|
/* Mark this thread as being in a transaction */
|
242 |
|
|
PFLAGS_SET_FSTRANS(&tp->t_pflags);
|
243 |
|
|
|
244 |
|
|
/*
|
245 |
|
|
* Attempt to reserve the needed disk blocks by decrementing
|
246 |
|
|
* the number needed from the number available. This will
|
247 |
|
|
* fail if the count would go below zero.
|
248 |
|
|
*/
|
249 |
|
|
if (blocks > 0) {
|
250 |
|
|
error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS,
|
251 |
|
|
-blocks, rsvd);
|
252 |
|
|
if (error != 0) {
|
253 |
|
|
PFLAGS_RESTORE(&tp->t_pflags);
|
254 |
|
|
return (XFS_ERROR(ENOSPC));
|
255 |
|
|
}
|
256 |
|
|
tp->t_blk_res += blocks;
|
257 |
|
|
}
|
258 |
|
|
|
259 |
|
|
/*
|
260 |
|
|
* Reserve the log space needed for this transaction.
|
261 |
|
|
*/
|
262 |
|
|
if (logspace > 0) {
|
263 |
|
|
ASSERT((tp->t_log_res == 0) || (tp->t_log_res == logspace));
|
264 |
|
|
ASSERT((tp->t_log_count == 0) ||
|
265 |
|
|
(tp->t_log_count == logcount));
|
266 |
|
|
if (flags & XFS_TRANS_PERM_LOG_RES) {
|
267 |
|
|
log_flags = XFS_LOG_PERM_RESERV;
|
268 |
|
|
tp->t_flags |= XFS_TRANS_PERM_LOG_RES;
|
269 |
|
|
} else {
|
270 |
|
|
ASSERT(tp->t_ticket == NULL);
|
271 |
|
|
ASSERT(!(tp->t_flags & XFS_TRANS_PERM_LOG_RES));
|
272 |
|
|
log_flags = 0;
|
273 |
|
|
}
|
274 |
|
|
|
275 |
|
|
error = xfs_log_reserve(tp->t_mountp, logspace, logcount,
|
276 |
|
|
&tp->t_ticket,
|
277 |
|
|
XFS_TRANSACTION, log_flags);
|
278 |
|
|
if (error) {
|
279 |
|
|
goto undo_blocks;
|
280 |
|
|
}
|
281 |
|
|
tp->t_log_res = logspace;
|
282 |
|
|
tp->t_log_count = logcount;
|
283 |
|
|
}
|
284 |
|
|
|
285 |
|
|
/*
|
286 |
|
|
* Attempt to reserve the needed realtime extents by decrementing
|
287 |
|
|
* the number needed from the number available. This will
|
288 |
|
|
* fail if the count would go below zero.
|
289 |
|
|
*/
|
290 |
|
|
if (rtextents > 0) {
|
291 |
|
|
error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FREXTENTS,
|
292 |
|
|
-rtextents, rsvd);
|
293 |
|
|
if (error) {
|
294 |
|
|
error = XFS_ERROR(ENOSPC);
|
295 |
|
|
goto undo_log;
|
296 |
|
|
}
|
297 |
|
|
tp->t_rtx_res += rtextents;
|
298 |
|
|
}
|
299 |
|
|
|
300 |
|
|
return 0;
|
301 |
|
|
|
302 |
|
|
/*
|
303 |
|
|
* Error cases jump to one of these labels to undo any
|
304 |
|
|
* reservations which have already been performed.
|
305 |
|
|
*/
|
306 |
|
|
undo_log:
|
307 |
|
|
if (logspace > 0) {
|
308 |
|
|
if (flags & XFS_TRANS_PERM_LOG_RES) {
|
309 |
|
|
log_flags = XFS_LOG_REL_PERM_RESERV;
|
310 |
|
|
} else {
|
311 |
|
|
log_flags = 0;
|
312 |
|
|
}
|
313 |
|
|
xfs_log_done(tp->t_mountp, tp->t_ticket, NULL, log_flags);
|
314 |
|
|
tp->t_ticket = NULL;
|
315 |
|
|
tp->t_log_res = 0;
|
316 |
|
|
tp->t_flags &= ~XFS_TRANS_PERM_LOG_RES;
|
317 |
|
|
}
|
318 |
|
|
|
319 |
|
|
undo_blocks:
|
320 |
|
|
if (blocks > 0) {
|
321 |
|
|
(void) xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS,
|
322 |
|
|
blocks, rsvd);
|
323 |
|
|
tp->t_blk_res = 0;
|
324 |
|
|
}
|
325 |
|
|
|
326 |
|
|
PFLAGS_RESTORE(&tp->t_pflags);
|
327 |
|
|
|
328 |
|
|
return (error);
|
329 |
|
|
}
|
330 |
|
|
|
331 |
|
|
|
332 |
|
|
/*
|
333 |
|
|
* This is called to set the a callback to be called when the given
|
334 |
|
|
* transaction is committed to disk. The transaction pointer and the
|
335 |
|
|
* argument pointer will be passed to the callback routine.
|
336 |
|
|
*
|
337 |
|
|
* Only one callback can be associated with any single transaction.
|
338 |
|
|
*/
|
339 |
|
|
void
|
340 |
|
|
xfs_trans_callback(
|
341 |
|
|
xfs_trans_t *tp,
|
342 |
|
|
xfs_trans_callback_t callback,
|
343 |
|
|
void *arg)
|
344 |
|
|
{
|
345 |
|
|
ASSERT(tp->t_callback == NULL);
|
346 |
|
|
tp->t_callback = callback;
|
347 |
|
|
tp->t_callarg = arg;
|
348 |
|
|
}
|
349 |
|
|
|
350 |
|
|
|
351 |
|
|
/*
|
352 |
|
|
* Record the indicated change to the given field for application
|
353 |
|
|
* to the file system's superblock when the transaction commits.
|
354 |
|
|
* For now, just store the change in the transaction structure.
|
355 |
|
|
*
|
356 |
|
|
* Mark the transaction structure to indicate that the superblock
|
357 |
|
|
* needs to be updated before committing.
|
358 |
|
|
*/
|
359 |
|
|
void
|
360 |
|
|
xfs_trans_mod_sb(
|
361 |
|
|
xfs_trans_t *tp,
|
362 |
|
|
uint field,
|
363 |
|
|
long delta)
|
364 |
|
|
{
|
365 |
|
|
|
366 |
|
|
switch (field) {
|
367 |
|
|
case XFS_TRANS_SB_ICOUNT:
|
368 |
|
|
tp->t_icount_delta += delta;
|
369 |
|
|
break;
|
370 |
|
|
case XFS_TRANS_SB_IFREE:
|
371 |
|
|
tp->t_ifree_delta += delta;
|
372 |
|
|
break;
|
373 |
|
|
case XFS_TRANS_SB_FDBLOCKS:
|
374 |
|
|
/*
|
375 |
|
|
* Track the number of blocks allocated in the
|
376 |
|
|
* transaction. Make sure it does not exceed the
|
377 |
|
|
* number reserved.
|
378 |
|
|
*/
|
379 |
|
|
if (delta < 0) {
|
380 |
|
|
tp->t_blk_res_used += (uint)-delta;
|
381 |
|
|
ASSERT(tp->t_blk_res_used <= tp->t_blk_res);
|
382 |
|
|
}
|
383 |
|
|
tp->t_fdblocks_delta += delta;
|
384 |
|
|
break;
|
385 |
|
|
case XFS_TRANS_SB_RES_FDBLOCKS:
|
386 |
|
|
/*
|
387 |
|
|
* The allocation has already been applied to the
|
388 |
|
|
* in-core superblock's counter. This should only
|
389 |
|
|
* be applied to the on-disk superblock.
|
390 |
|
|
*/
|
391 |
|
|
ASSERT(delta < 0);
|
392 |
|
|
tp->t_res_fdblocks_delta += delta;
|
393 |
|
|
break;
|
394 |
|
|
case XFS_TRANS_SB_FREXTENTS:
|
395 |
|
|
/*
|
396 |
|
|
* Track the number of blocks allocated in the
|
397 |
|
|
* transaction. Make sure it does not exceed the
|
398 |
|
|
* number reserved.
|
399 |
|
|
*/
|
400 |
|
|
if (delta < 0) {
|
401 |
|
|
tp->t_rtx_res_used += (uint)-delta;
|
402 |
|
|
ASSERT(tp->t_rtx_res_used <= tp->t_rtx_res);
|
403 |
|
|
}
|
404 |
|
|
tp->t_frextents_delta += delta;
|
405 |
|
|
break;
|
406 |
|
|
case XFS_TRANS_SB_RES_FREXTENTS:
|
407 |
|
|
/*
|
408 |
|
|
* The allocation has already been applied to the
|
409 |
|
|
* in-core superblocks's counter. This should only
|
410 |
|
|
* be applied to the on-disk superblock.
|
411 |
|
|
*/
|
412 |
|
|
ASSERT(delta < 0);
|
413 |
|
|
tp->t_res_frextents_delta += delta;
|
414 |
|
|
break;
|
415 |
|
|
case XFS_TRANS_SB_DBLOCKS:
|
416 |
|
|
ASSERT(delta > 0);
|
417 |
|
|
tp->t_dblocks_delta += delta;
|
418 |
|
|
break;
|
419 |
|
|
case XFS_TRANS_SB_AGCOUNT:
|
420 |
|
|
ASSERT(delta > 0);
|
421 |
|
|
tp->t_agcount_delta += delta;
|
422 |
|
|
break;
|
423 |
|
|
case XFS_TRANS_SB_IMAXPCT:
|
424 |
|
|
tp->t_imaxpct_delta += delta;
|
425 |
|
|
break;
|
426 |
|
|
case XFS_TRANS_SB_REXTSIZE:
|
427 |
|
|
tp->t_rextsize_delta += delta;
|
428 |
|
|
break;
|
429 |
|
|
case XFS_TRANS_SB_RBMBLOCKS:
|
430 |
|
|
tp->t_rbmblocks_delta += delta;
|
431 |
|
|
break;
|
432 |
|
|
case XFS_TRANS_SB_RBLOCKS:
|
433 |
|
|
tp->t_rblocks_delta += delta;
|
434 |
|
|
break;
|
435 |
|
|
case XFS_TRANS_SB_REXTENTS:
|
436 |
|
|
tp->t_rextents_delta += delta;
|
437 |
|
|
break;
|
438 |
|
|
case XFS_TRANS_SB_REXTSLOG:
|
439 |
|
|
tp->t_rextslog_delta += delta;
|
440 |
|
|
break;
|
441 |
|
|
default:
|
442 |
|
|
ASSERT(0);
|
443 |
|
|
return;
|
444 |
|
|
}
|
445 |
|
|
|
446 |
|
|
tp->t_flags |= (XFS_TRANS_SB_DIRTY | XFS_TRANS_DIRTY);
|
447 |
|
|
}
|
448 |
|
|
|
449 |
|
|
/*
|
450 |
|
|
* xfs_trans_apply_sb_deltas() is called from the commit code
|
451 |
|
|
* to bring the superblock buffer into the current transaction
|
452 |
|
|
* and modify it as requested by earlier calls to xfs_trans_mod_sb().
|
453 |
|
|
*
|
454 |
|
|
* For now we just look at each field allowed to change and change
|
455 |
|
|
* it if necessary.
|
456 |
|
|
*/
|
457 |
|
|
STATIC void
|
458 |
|
|
xfs_trans_apply_sb_deltas(
|
459 |
|
|
xfs_trans_t *tp)
|
460 |
|
|
{
|
461 |
|
|
xfs_sb_t *sbp;
|
462 |
|
|
xfs_buf_t *bp;
|
463 |
|
|
int whole = 0;
|
464 |
|
|
|
465 |
|
|
bp = xfs_trans_getsb(tp, tp->t_mountp, 0);
|
466 |
|
|
sbp = XFS_BUF_TO_SBP(bp);
|
467 |
|
|
|
468 |
|
|
/*
|
469 |
|
|
* Check that superblock mods match the mods made to AGF counters.
|
470 |
|
|
*/
|
471 |
|
|
ASSERT((tp->t_fdblocks_delta + tp->t_res_fdblocks_delta) ==
|
472 |
|
|
(tp->t_ag_freeblks_delta + tp->t_ag_flist_delta +
|
473 |
|
|
tp->t_ag_btree_delta));
|
474 |
|
|
|
475 |
|
|
if (tp->t_icount_delta != 0) {
|
476 |
|
|
INT_MOD(sbp->sb_icount, ARCH_CONVERT, tp->t_icount_delta);
|
477 |
|
|
}
|
478 |
|
|
if (tp->t_ifree_delta != 0) {
|
479 |
|
|
INT_MOD(sbp->sb_ifree, ARCH_CONVERT, tp->t_ifree_delta);
|
480 |
|
|
}
|
481 |
|
|
|
482 |
|
|
if (tp->t_fdblocks_delta != 0) {
|
483 |
|
|
INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_fdblocks_delta);
|
484 |
|
|
}
|
485 |
|
|
if (tp->t_res_fdblocks_delta != 0) {
|
486 |
|
|
INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_res_fdblocks_delta);
|
487 |
|
|
}
|
488 |
|
|
|
489 |
|
|
if (tp->t_frextents_delta != 0) {
|
490 |
|
|
INT_MOD(sbp->sb_frextents, ARCH_CONVERT, tp->t_frextents_delta);
|
491 |
|
|
}
|
492 |
|
|
if (tp->t_dblocks_delta != 0) {
|
493 |
|
|
INT_MOD(sbp->sb_dblocks, ARCH_CONVERT, tp->t_dblocks_delta);
|
494 |
|
|
whole = 1;
|
495 |
|
|
}
|
496 |
|
|
if (tp->t_agcount_delta != 0) {
|
497 |
|
|
INT_MOD(sbp->sb_agcount, ARCH_CONVERT, tp->t_agcount_delta);
|
498 |
|
|
whole = 1;
|
499 |
|
|
}
|
500 |
|
|
if (tp->t_imaxpct_delta != 0) {
|
501 |
|
|
INT_MOD(sbp->sb_imax_pct, ARCH_CONVERT, tp->t_imaxpct_delta);
|
502 |
|
|
whole = 1;
|
503 |
|
|
}
|
504 |
|
|
if (tp->t_rextsize_delta != 0) {
|
505 |
|
|
INT_MOD(sbp->sb_rextsize, ARCH_CONVERT, tp->t_rextsize_delta);
|
506 |
|
|
whole = 1;
|
507 |
|
|
}
|
508 |
|
|
if (tp->t_rbmblocks_delta != 0) {
|
509 |
|
|
INT_MOD(sbp->sb_rbmblocks, ARCH_CONVERT, tp->t_rbmblocks_delta);
|
510 |
|
|
whole = 1;
|
511 |
|
|
}
|
512 |
|
|
if (tp->t_rblocks_delta != 0) {
|
513 |
|
|
INT_MOD(sbp->sb_rblocks, ARCH_CONVERT, tp->t_rblocks_delta);
|
514 |
|
|
whole = 1;
|
515 |
|
|
}
|
516 |
|
|
if (tp->t_rextents_delta != 0) {
|
517 |
|
|
INT_MOD(sbp->sb_rextents, ARCH_CONVERT, tp->t_rextents_delta);
|
518 |
|
|
whole = 1;
|
519 |
|
|
}
|
520 |
|
|
if (tp->t_rextslog_delta != 0) {
|
521 |
|
|
INT_MOD(sbp->sb_rextslog, ARCH_CONVERT, tp->t_rextslog_delta);
|
522 |
|
|
whole = 1;
|
523 |
|
|
}
|
524 |
|
|
|
525 |
|
|
if (whole)
|
526 |
|
|
/*
|
527 |
|
|
* Log the whole thing, the fields are discontiguous.
|
528 |
|
|
*/
|
529 |
|
|
xfs_trans_log_buf(tp, bp, 0, sizeof(xfs_sb_t) - 1);
|
530 |
|
|
else
|
531 |
|
|
/*
|
532 |
|
|
* Since all the modifiable fields are contiguous, we
|
533 |
|
|
* can get away with this.
|
534 |
|
|
*/
|
535 |
|
|
xfs_trans_log_buf(tp, bp, offsetof(xfs_sb_t, sb_icount),
|
536 |
|
|
offsetof(xfs_sb_t, sb_frextents) +
|
537 |
|
|
sizeof(sbp->sb_frextents) - 1);
|
538 |
|
|
|
539 |
|
|
XFS_MTOVFS(tp->t_mountp)->vfs_super->s_dirt = 1;
|
540 |
|
|
}
|
541 |
|
|
|
542 |
|
|
/*
|
543 |
|
|
* xfs_trans_unreserve_and_mod_sb() is called to release unused
|
544 |
|
|
* reservations and apply superblock counter changes to the in-core
|
545 |
|
|
* superblock.
|
546 |
|
|
*
|
547 |
|
|
* This is done efficiently with a single call to xfs_mod_incore_sb_batch().
|
548 |
|
|
*/
|
549 |
|
|
void
|
550 |
|
|
xfs_trans_unreserve_and_mod_sb(
|
551 |
|
|
xfs_trans_t *tp)
|
552 |
|
|
{
|
553 |
|
|
xfs_mod_sb_t msb[14]; /* If you add cases, add entries */
|
554 |
|
|
xfs_mod_sb_t *msbp;
|
555 |
|
|
/* REFERENCED */
|
556 |
|
|
int error;
|
557 |
|
|
int rsvd;
|
558 |
|
|
|
559 |
|
|
msbp = msb;
|
560 |
|
|
rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
|
561 |
|
|
|
562 |
|
|
/*
|
563 |
|
|
* Release any reserved blocks. Any that were allocated
|
564 |
|
|
* will be taken back again by fdblocks_delta below.
|
565 |
|
|
*/
|
566 |
|
|
if (tp->t_blk_res > 0) {
|
567 |
|
|
msbp->msb_field = XFS_SBS_FDBLOCKS;
|
568 |
|
|
msbp->msb_delta = tp->t_blk_res;
|
569 |
|
|
msbp++;
|
570 |
|
|
}
|
571 |
|
|
|
572 |
|
|
/*
|
573 |
|
|
* Release any reserved real time extents . Any that were
|
574 |
|
|
* allocated will be taken back again by frextents_delta below.
|
575 |
|
|
*/
|
576 |
|
|
if (tp->t_rtx_res > 0) {
|
577 |
|
|
msbp->msb_field = XFS_SBS_FREXTENTS;
|
578 |
|
|
msbp->msb_delta = tp->t_rtx_res;
|
579 |
|
|
msbp++;
|
580 |
|
|
}
|
581 |
|
|
|
582 |
|
|
/*
|
583 |
|
|
* Apply any superblock modifications to the in-core version.
|
584 |
|
|
* The t_res_fdblocks_delta and t_res_frextents_delta fields are
|
585 |
|
|
* explicity NOT applied to the in-core superblock.
|
586 |
|
|
* The idea is that that has already been done.
|
587 |
|
|
*/
|
588 |
|
|
if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
|
589 |
|
|
if (tp->t_icount_delta != 0) {
|
590 |
|
|
msbp->msb_field = XFS_SBS_ICOUNT;
|
591 |
|
|
msbp->msb_delta = (int)tp->t_icount_delta;
|
592 |
|
|
msbp++;
|
593 |
|
|
}
|
594 |
|
|
if (tp->t_ifree_delta != 0) {
|
595 |
|
|
msbp->msb_field = XFS_SBS_IFREE;
|
596 |
|
|
msbp->msb_delta = (int)tp->t_ifree_delta;
|
597 |
|
|
msbp++;
|
598 |
|
|
}
|
599 |
|
|
if (tp->t_fdblocks_delta != 0) {
|
600 |
|
|
msbp->msb_field = XFS_SBS_FDBLOCKS;
|
601 |
|
|
msbp->msb_delta = (int)tp->t_fdblocks_delta;
|
602 |
|
|
msbp++;
|
603 |
|
|
}
|
604 |
|
|
if (tp->t_frextents_delta != 0) {
|
605 |
|
|
msbp->msb_field = XFS_SBS_FREXTENTS;
|
606 |
|
|
msbp->msb_delta = (int)tp->t_frextents_delta;
|
607 |
|
|
msbp++;
|
608 |
|
|
}
|
609 |
|
|
if (tp->t_dblocks_delta != 0) {
|
610 |
|
|
msbp->msb_field = XFS_SBS_DBLOCKS;
|
611 |
|
|
msbp->msb_delta = (int)tp->t_dblocks_delta;
|
612 |
|
|
msbp++;
|
613 |
|
|
}
|
614 |
|
|
if (tp->t_agcount_delta != 0) {
|
615 |
|
|
msbp->msb_field = XFS_SBS_AGCOUNT;
|
616 |
|
|
msbp->msb_delta = (int)tp->t_agcount_delta;
|
617 |
|
|
msbp++;
|
618 |
|
|
}
|
619 |
|
|
if (tp->t_imaxpct_delta != 0) {
|
620 |
|
|
msbp->msb_field = XFS_SBS_IMAX_PCT;
|
621 |
|
|
msbp->msb_delta = (int)tp->t_imaxpct_delta;
|
622 |
|
|
msbp++;
|
623 |
|
|
}
|
624 |
|
|
if (tp->t_rextsize_delta != 0) {
|
625 |
|
|
msbp->msb_field = XFS_SBS_REXTSIZE;
|
626 |
|
|
msbp->msb_delta = (int)tp->t_rextsize_delta;
|
627 |
|
|
msbp++;
|
628 |
|
|
}
|
629 |
|
|
if (tp->t_rbmblocks_delta != 0) {
|
630 |
|
|
msbp->msb_field = XFS_SBS_RBMBLOCKS;
|
631 |
|
|
msbp->msb_delta = (int)tp->t_rbmblocks_delta;
|
632 |
|
|
msbp++;
|
633 |
|
|
}
|
634 |
|
|
if (tp->t_rblocks_delta != 0) {
|
635 |
|
|
msbp->msb_field = XFS_SBS_RBLOCKS;
|
636 |
|
|
msbp->msb_delta = (int)tp->t_rblocks_delta;
|
637 |
|
|
msbp++;
|
638 |
|
|
}
|
639 |
|
|
if (tp->t_rextents_delta != 0) {
|
640 |
|
|
msbp->msb_field = XFS_SBS_REXTENTS;
|
641 |
|
|
msbp->msb_delta = (int)tp->t_rextents_delta;
|
642 |
|
|
msbp++;
|
643 |
|
|
}
|
644 |
|
|
if (tp->t_rextslog_delta != 0) {
|
645 |
|
|
msbp->msb_field = XFS_SBS_REXTSLOG;
|
646 |
|
|
msbp->msb_delta = (int)tp->t_rextslog_delta;
|
647 |
|
|
msbp++;
|
648 |
|
|
}
|
649 |
|
|
}
|
650 |
|
|
|
651 |
|
|
/*
|
652 |
|
|
* If we need to change anything, do it.
|
653 |
|
|
*/
|
654 |
|
|
if (msbp > msb) {
|
655 |
|
|
error = xfs_mod_incore_sb_batch(tp->t_mountp, msb,
|
656 |
|
|
(uint)(msbp - msb), rsvd);
|
657 |
|
|
ASSERT(error == 0);
|
658 |
|
|
}
|
659 |
|
|
}
|
660 |
|
|
|
661 |
|
|
|
662 |
|
|
/*
|
663 |
|
|
* xfs_trans_commit
|
664 |
|
|
*
|
665 |
|
|
* Commit the given transaction to the log a/synchronously.
|
666 |
|
|
*
|
667 |
|
|
* XFS disk error handling mechanism is not based on a typical
|
668 |
|
|
* transaction abort mechanism. Logically after the filesystem
|
669 |
|
|
* gets marked 'SHUTDOWN', we can't let any new transactions
|
670 |
|
|
* be durable - ie. committed to disk - because some metadata might
|
671 |
|
|
* be inconsistent. In such cases, this returns an error, and the
|
672 |
|
|
* caller may assume that all locked objects joined to the transaction
|
673 |
|
|
* have already been unlocked as if the commit had succeeded.
|
674 |
|
|
* Do not reference the transaction structure after this call.
|
675 |
|
|
*/
|
676 |
|
|
/*ARGSUSED*/
|
677 |
|
|
int
|
678 |
|
|
xfs_trans_commit(
|
679 |
|
|
xfs_trans_t *tp,
|
680 |
|
|
uint flags,
|
681 |
|
|
xfs_lsn_t *commit_lsn_p)
|
682 |
|
|
{
|
683 |
|
|
xfs_log_iovec_t *log_vector;
|
684 |
|
|
int nvec;
|
685 |
|
|
xfs_mount_t *mp;
|
686 |
|
|
xfs_lsn_t commit_lsn;
|
687 |
|
|
/* REFERENCED */
|
688 |
|
|
int error;
|
689 |
|
|
int log_flags;
|
690 |
|
|
int sync;
|
691 |
|
|
#define XFS_TRANS_LOGVEC_COUNT 16
|
692 |
|
|
xfs_log_iovec_t log_vector_fast[XFS_TRANS_LOGVEC_COUNT];
|
693 |
|
|
#if defined(XLOG_NOLOG) || defined(DEBUG)
|
694 |
|
|
static xfs_lsn_t trans_lsn = 1;
|
695 |
|
|
#endif
|
696 |
|
|
void *commit_iclog;
|
697 |
|
|
int shutdown;
|
698 |
|
|
|
699 |
|
|
commit_lsn = -1;
|
700 |
|
|
|
701 |
|
|
/*
|
702 |
|
|
* Determine whether this commit is releasing a permanent
|
703 |
|
|
* log reservation or not.
|
704 |
|
|
*/
|
705 |
|
|
if (flags & XFS_TRANS_RELEASE_LOG_RES) {
|
706 |
|
|
ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
|
707 |
|
|
log_flags = XFS_LOG_REL_PERM_RESERV;
|
708 |
|
|
} else {
|
709 |
|
|
log_flags = 0;
|
710 |
|
|
}
|
711 |
|
|
mp = tp->t_mountp;
|
712 |
|
|
|
713 |
|
|
/*
|
714 |
|
|
* If there is nothing to be logged by the transaction,
|
715 |
|
|
* then unlock all of the items associated with the
|
716 |
|
|
* transaction and free the transaction structure.
|
717 |
|
|
* Also make sure to return any reserved blocks to
|
718 |
|
|
* the free pool.
|
719 |
|
|
*/
|
720 |
|
|
shut_us_down:
|
721 |
|
|
shutdown = XFS_FORCED_SHUTDOWN(mp) ? EIO : 0;
|
722 |
|
|
if (!(tp->t_flags & XFS_TRANS_DIRTY) || shutdown) {
|
723 |
|
|
xfs_trans_unreserve_and_mod_sb(tp);
|
724 |
|
|
/*
|
725 |
|
|
* It is indeed possible for the transaction to be
|
726 |
|
|
* not dirty but the dqinfo portion to be. All that
|
727 |
|
|
* means is that we have some (non-persistent) quota
|
728 |
|
|
* reservations that need to be unreserved.
|
729 |
|
|
*/
|
730 |
|
|
XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp);
|
731 |
|
|
if (tp->t_ticket) {
|
732 |
|
|
commit_lsn = xfs_log_done(mp, tp->t_ticket,
|
733 |
|
|
NULL, log_flags);
|
734 |
|
|
if (commit_lsn == -1 && !shutdown)
|
735 |
|
|
shutdown = XFS_ERROR(EIO);
|
736 |
|
|
}
|
737 |
|
|
PFLAGS_RESTORE(&tp->t_pflags);
|
738 |
|
|
xfs_trans_free_items(tp, shutdown? XFS_TRANS_ABORT : 0);
|
739 |
|
|
xfs_trans_free_busy(tp);
|
740 |
|
|
xfs_trans_free(tp);
|
741 |
|
|
XFS_STATS_INC(xs_trans_empty);
|
742 |
|
|
if (commit_lsn_p)
|
743 |
|
|
*commit_lsn_p = commit_lsn;
|
744 |
|
|
return (shutdown);
|
745 |
|
|
}
|
746 |
|
|
#if defined(XLOG_NOLOG) || defined(DEBUG)
|
747 |
|
|
ASSERT(!xlog_debug || tp->t_ticket != NULL);
|
748 |
|
|
#else
|
749 |
|
|
ASSERT(tp->t_ticket != NULL);
|
750 |
|
|
#endif
|
751 |
|
|
|
752 |
|
|
/*
|
753 |
|
|
* If we need to update the superblock, then do it now.
|
754 |
|
|
*/
|
755 |
|
|
if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
|
756 |
|
|
xfs_trans_apply_sb_deltas(tp);
|
757 |
|
|
}
|
758 |
|
|
XFS_TRANS_APPLY_DQUOT_DELTAS(mp, tp);
|
759 |
|
|
|
760 |
|
|
/*
|
761 |
|
|
* Ask each log item how many log_vector entries it will
|
762 |
|
|
* need so we can figure out how many to allocate.
|
763 |
|
|
* Try to avoid the kmem_alloc() call in the common case
|
764 |
|
|
* by using a vector from the stack when it fits.
|
765 |
|
|
*/
|
766 |
|
|
nvec = xfs_trans_count_vecs(tp);
|
767 |
|
|
|
768 |
|
|
if (nvec == 0) {
|
769 |
|
|
xfs_force_shutdown(mp, XFS_LOG_IO_ERROR);
|
770 |
|
|
goto shut_us_down;
|
771 |
|
|
}
|
772 |
|
|
|
773 |
|
|
|
774 |
|
|
if (nvec <= XFS_TRANS_LOGVEC_COUNT) {
|
775 |
|
|
log_vector = log_vector_fast;
|
776 |
|
|
} else {
|
777 |
|
|
log_vector = (xfs_log_iovec_t *)kmem_alloc(nvec *
|
778 |
|
|
sizeof(xfs_log_iovec_t),
|
779 |
|
|
KM_SLEEP);
|
780 |
|
|
}
|
781 |
|
|
|
782 |
|
|
/*
|
783 |
|
|
* Fill in the log_vector and pin the logged items, and
|
784 |
|
|
* then write the transaction to the log.
|
785 |
|
|
*/
|
786 |
|
|
xfs_trans_fill_vecs(tp, log_vector);
|
787 |
|
|
|
788 |
|
|
/*
|
789 |
|
|
* Ignore errors here. xfs_log_done would do the right thing.
|
790 |
|
|
* We need to put the ticket, etc. away.
|
791 |
|
|
*/
|
792 |
|
|
error = xfs_log_write(mp, log_vector, nvec, tp->t_ticket,
|
793 |
|
|
&(tp->t_lsn));
|
794 |
|
|
|
795 |
|
|
#if defined(XLOG_NOLOG) || defined(DEBUG)
|
796 |
|
|
if (xlog_debug) {
|
797 |
|
|
commit_lsn = xfs_log_done(mp, tp->t_ticket,
|
798 |
|
|
&commit_iclog, log_flags);
|
799 |
|
|
} else {
|
800 |
|
|
commit_lsn = 0;
|
801 |
|
|
tp->t_lsn = trans_lsn++;
|
802 |
|
|
}
|
803 |
|
|
#else
|
804 |
|
|
/*
|
805 |
|
|
* This is the regular case. At this point (after the call finishes),
|
806 |
|
|
* the transaction is committed incore and could go out to disk at
|
807 |
|
|
* any time. However, all the items associated with the transaction
|
808 |
|
|
* are still locked and pinned in memory.
|
809 |
|
|
*/
|
810 |
|
|
commit_lsn = xfs_log_done(mp, tp->t_ticket, &commit_iclog, log_flags);
|
811 |
|
|
#endif
|
812 |
|
|
|
813 |
|
|
tp->t_commit_lsn = commit_lsn;
|
814 |
|
|
if (nvec > XFS_TRANS_LOGVEC_COUNT) {
|
815 |
|
|
kmem_free(log_vector, nvec * sizeof(xfs_log_iovec_t));
|
816 |
|
|
}
|
817 |
|
|
|
818 |
|
|
if (commit_lsn_p)
|
819 |
|
|
*commit_lsn_p = commit_lsn;
|
820 |
|
|
|
821 |
|
|
/*
|
822 |
|
|
* If we got a log write error. Unpin the logitems that we
|
823 |
|
|
* had pinned, clean up, free trans structure, and return error.
|
824 |
|
|
*/
|
825 |
|
|
if (error || commit_lsn == -1) {
|
826 |
|
|
PFLAGS_RESTORE(&tp->t_pflags);
|
827 |
|
|
xfs_trans_uncommit(tp, flags|XFS_TRANS_ABORT);
|
828 |
|
|
return XFS_ERROR(EIO);
|
829 |
|
|
}
|
830 |
|
|
|
831 |
|
|
/*
|
832 |
|
|
* Once the transaction has committed, unused
|
833 |
|
|
* reservations need to be released and changes to
|
834 |
|
|
* the superblock need to be reflected in the in-core
|
835 |
|
|
* version. Do that now.
|
836 |
|
|
*/
|
837 |
|
|
xfs_trans_unreserve_and_mod_sb(tp);
|
838 |
|
|
|
839 |
|
|
sync = tp->t_flags & XFS_TRANS_SYNC;
|
840 |
|
|
|
841 |
|
|
/*
|
842 |
|
|
* Tell the LM to call the transaction completion routine
|
843 |
|
|
* when the log write with LSN commit_lsn completes (e.g.
|
844 |
|
|
* when the transaction commit really hits the on-disk log).
|
845 |
|
|
* After this call we cannot reference tp, because the call
|
846 |
|
|
* can happen at any time and the call will free the transaction
|
847 |
|
|
* structure pointed to by tp. The only case where we call
|
848 |
|
|
* the completion routine (xfs_trans_committed) directly is
|
849 |
|
|
* if the log is turned off on a debug kernel or we're
|
850 |
|
|
* running in simulation mode (the log is explicitly turned
|
851 |
|
|
* off).
|
852 |
|
|
*/
|
853 |
|
|
tp->t_logcb.cb_func = (void(*)(void*, int))xfs_trans_committed;
|
854 |
|
|
tp->t_logcb.cb_arg = tp;
|
855 |
|
|
|
856 |
|
|
/* We need to pass the iclog buffer which was used for the
|
857 |
|
|
* transaction commit record into this function, and attach
|
858 |
|
|
* the callback to it. The callback must be attached before
|
859 |
|
|
* the items are unlocked to avoid racing with other threads
|
860 |
|
|
* waiting for an item to unlock.
|
861 |
|
|
*/
|
862 |
|
|
error = xfs_log_notify(mp, commit_iclog, &(tp->t_logcb));
|
863 |
|
|
|
864 |
|
|
/* mark this thread as no longer being in a transaction */
|
865 |
|
|
PFLAGS_RESTORE(&tp->t_pflags);
|
866 |
|
|
|
867 |
|
|
/*
|
868 |
|
|
* Once all the items of the transaction have been copied
|
869 |
|
|
* to the in core log and the callback is attached, the
|
870 |
|
|
* items can be unlocked.
|
871 |
|
|
*
|
872 |
|
|
* This will free descriptors pointing to items which were
|
873 |
|
|
* not logged since there is nothing more to do with them.
|
874 |
|
|
* For items which were logged, we will keep pointers to them
|
875 |
|
|
* so they can be unpinned after the transaction commits to disk.
|
876 |
|
|
* This will also stamp each modified meta-data item with
|
877 |
|
|
* the commit lsn of this transaction for dependency tracking
|
878 |
|
|
* purposes.
|
879 |
|
|
*/
|
880 |
|
|
xfs_trans_unlock_items(tp, commit_lsn);
|
881 |
|
|
|
882 |
|
|
/*
|
883 |
|
|
* Now that the xfs_trans_committed callback has been attached,
|
884 |
|
|
* and the items are released we can finally allow the iclog to
|
885 |
|
|
* go to disk.
|
886 |
|
|
*/
|
887 |
|
|
error = xfs_log_release_iclog(mp, commit_iclog);
|
888 |
|
|
|
889 |
|
|
/*
|
890 |
|
|
* If the transaction needs to be synchronous, then force the
|
891 |
|
|
* log out now and wait for it.
|
892 |
|
|
*/
|
893 |
|
|
if (sync) {
|
894 |
|
|
if (!error)
|
895 |
|
|
error = xfs_log_force(mp, commit_lsn,
|
896 |
|
|
XFS_LOG_FORCE | XFS_LOG_SYNC);
|
897 |
|
|
XFS_STATS_INC(xs_trans_sync);
|
898 |
|
|
} else {
|
899 |
|
|
XFS_STATS_INC(xs_trans_async);
|
900 |
|
|
}
|
901 |
|
|
|
902 |
|
|
return (error);
|
903 |
|
|
}
|
904 |
|
|
|
905 |
|
|
|
906 |
|
|
/*
|
907 |
|
|
* Total up the number of log iovecs needed to commit this
|
908 |
|
|
* transaction. The transaction itself needs one for the
|
909 |
|
|
* transaction header. Ask each dirty item in turn how many
|
910 |
|
|
* it needs to get the total.
|
911 |
|
|
*/
|
912 |
|
|
STATIC uint
|
913 |
|
|
xfs_trans_count_vecs(
|
914 |
|
|
xfs_trans_t *tp)
|
915 |
|
|
{
|
916 |
|
|
int nvecs;
|
917 |
|
|
xfs_log_item_desc_t *lidp;
|
918 |
|
|
|
919 |
|
|
nvecs = 1;
|
920 |
|
|
lidp = xfs_trans_first_item(tp);
|
921 |
|
|
ASSERT(lidp != NULL);
|
922 |
|
|
|
923 |
|
|
/* In the non-debug case we need to start bailing out if we
|
924 |
|
|
* didn't find a log_item here, return zero and let trans_commit
|
925 |
|
|
* deal with it.
|
926 |
|
|
*/
|
927 |
|
|
if (lidp == NULL)
|
928 |
|
|
return 0;
|
929 |
|
|
|
930 |
|
|
while (lidp != NULL) {
|
931 |
|
|
/*
|
932 |
|
|
* Skip items which aren't dirty in this transaction.
|
933 |
|
|
*/
|
934 |
|
|
if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
|
935 |
|
|
lidp = xfs_trans_next_item(tp, lidp);
|
936 |
|
|
continue;
|
937 |
|
|
}
|
938 |
|
|
lidp->lid_size = IOP_SIZE(lidp->lid_item);
|
939 |
|
|
nvecs += lidp->lid_size;
|
940 |
|
|
lidp = xfs_trans_next_item(tp, lidp);
|
941 |
|
|
}
|
942 |
|
|
|
943 |
|
|
return nvecs;
|
944 |
|
|
}
|
945 |
|
|
|
946 |
|
|
/*
|
947 |
|
|
* Called from the trans_commit code when we notice that
|
948 |
|
|
* the filesystem is in the middle of a forced shutdown.
|
949 |
|
|
*/
|
950 |
|
|
STATIC void
|
951 |
|
|
xfs_trans_uncommit(
|
952 |
|
|
xfs_trans_t *tp,
|
953 |
|
|
uint flags)
|
954 |
|
|
{
|
955 |
|
|
xfs_log_item_desc_t *lidp;
|
956 |
|
|
|
957 |
|
|
for (lidp = xfs_trans_first_item(tp);
|
958 |
|
|
lidp != NULL;
|
959 |
|
|
lidp = xfs_trans_next_item(tp, lidp)) {
|
960 |
|
|
/*
|
961 |
|
|
* Unpin all but those that aren't dirty.
|
962 |
|
|
*/
|
963 |
|
|
if (lidp->lid_flags & XFS_LID_DIRTY)
|
964 |
|
|
IOP_UNPIN_REMOVE(lidp->lid_item, tp);
|
965 |
|
|
}
|
966 |
|
|
|
967 |
|
|
xfs_trans_unreserve_and_mod_sb(tp);
|
968 |
|
|
XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(tp->t_mountp, tp);
|
969 |
|
|
|
970 |
|
|
xfs_trans_free_items(tp, flags);
|
971 |
|
|
xfs_trans_free_busy(tp);
|
972 |
|
|
xfs_trans_free(tp);
|
973 |
|
|
}
|
974 |
|
|
|
975 |
|
|
/*
|
976 |
|
|
* Fill in the vector with pointers to data to be logged
|
977 |
|
|
* by this transaction. The transaction header takes
|
978 |
|
|
* the first vector, and then each dirty item takes the
|
979 |
|
|
* number of vectors it indicated it needed in xfs_trans_count_vecs().
|
980 |
|
|
*
|
981 |
|
|
* As each item fills in the entries it needs, also pin the item
|
982 |
|
|
* so that it cannot be flushed out until the log write completes.
|
983 |
|
|
*/
|
984 |
|
|
STATIC void
|
985 |
|
|
xfs_trans_fill_vecs(
|
986 |
|
|
xfs_trans_t *tp,
|
987 |
|
|
xfs_log_iovec_t *log_vector)
|
988 |
|
|
{
|
989 |
|
|
xfs_log_item_desc_t *lidp;
|
990 |
|
|
xfs_log_iovec_t *vecp;
|
991 |
|
|
uint nitems;
|
992 |
|
|
|
993 |
|
|
/*
|
994 |
|
|
* Skip over the entry for the transaction header, we'll
|
995 |
|
|
* fill that in at the end.
|
996 |
|
|
*/
|
997 |
|
|
vecp = log_vector + 1; /* pointer arithmetic */
|
998 |
|
|
|
999 |
|
|
nitems = 0;
|
1000 |
|
|
lidp = xfs_trans_first_item(tp);
|
1001 |
|
|
ASSERT(lidp != NULL);
|
1002 |
|
|
while (lidp != NULL) {
|
1003 |
|
|
/*
|
1004 |
|
|
* Skip items which aren't dirty in this transaction.
|
1005 |
|
|
*/
|
1006 |
|
|
if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
|
1007 |
|
|
lidp = xfs_trans_next_item(tp, lidp);
|
1008 |
|
|
continue;
|
1009 |
|
|
}
|
1010 |
|
|
/*
|
1011 |
|
|
* The item may be marked dirty but not log anything.
|
1012 |
|
|
* This can be used to get called when a transaction
|
1013 |
|
|
* is committed.
|
1014 |
|
|
*/
|
1015 |
|
|
if (lidp->lid_size) {
|
1016 |
|
|
nitems++;
|
1017 |
|
|
}
|
1018 |
|
|
IOP_FORMAT(lidp->lid_item, vecp);
|
1019 |
|
|
vecp += lidp->lid_size; /* pointer arithmetic */
|
1020 |
|
|
IOP_PIN(lidp->lid_item);
|
1021 |
|
|
lidp = xfs_trans_next_item(tp, lidp);
|
1022 |
|
|
}
|
1023 |
|
|
|
1024 |
|
|
/*
|
1025 |
|
|
* Now that we've counted the number of items in this
|
1026 |
|
|
* transaction, fill in the transaction header.
|
1027 |
|
|
*/
|
1028 |
|
|
tp->t_header.th_magic = XFS_TRANS_HEADER_MAGIC;
|
1029 |
|
|
tp->t_header.th_type = tp->t_type;
|
1030 |
|
|
tp->t_header.th_num_items = nitems;
|
1031 |
|
|
log_vector->i_addr = (xfs_caddr_t)&tp->t_header;
|
1032 |
|
|
log_vector->i_len = sizeof(xfs_trans_header_t);
|
1033 |
|
|
}
|
1034 |
|
|
|
1035 |
|
|
|
1036 |
|
|
/*
|
1037 |
|
|
* Unlock all of the transaction's items and free the transaction.
|
1038 |
|
|
* The transaction must not have modified any of its items, because
|
1039 |
|
|
* there is no way to restore them to their previous state.
|
1040 |
|
|
*
|
1041 |
|
|
* If the transaction has made a log reservation, make sure to release
|
1042 |
|
|
* it as well.
|
1043 |
|
|
*/
|
1044 |
|
|
void
|
1045 |
|
|
xfs_trans_cancel(
|
1046 |
|
|
xfs_trans_t *tp,
|
1047 |
|
|
int flags)
|
1048 |
|
|
{
|
1049 |
|
|
int log_flags;
|
1050 |
|
|
#ifdef DEBUG
|
1051 |
|
|
xfs_log_item_chunk_t *licp;
|
1052 |
|
|
xfs_log_item_desc_t *lidp;
|
1053 |
|
|
xfs_log_item_t *lip;
|
1054 |
|
|
int i;
|
1055 |
|
|
#endif
|
1056 |
|
|
|
1057 |
|
|
/*
|
1058 |
|
|
* See if the caller is being too lazy to figure out if
|
1059 |
|
|
* the transaction really needs an abort.
|
1060 |
|
|
*/
|
1061 |
|
|
if ((flags & XFS_TRANS_ABORT) && !(tp->t_flags & XFS_TRANS_DIRTY))
|
1062 |
|
|
flags &= ~XFS_TRANS_ABORT;
|
1063 |
|
|
/*
|
1064 |
|
|
* See if the caller is relying on us to shut down the
|
1065 |
|
|
* filesystem. This happens in paths where we detect
|
1066 |
|
|
* corruption and decide to give up.
|
1067 |
|
|
*/
|
1068 |
|
|
if ((tp->t_flags & XFS_TRANS_DIRTY) &&
|
1069 |
|
|
!XFS_FORCED_SHUTDOWN(tp->t_mountp))
|
1070 |
|
|
xfs_force_shutdown(tp->t_mountp, XFS_CORRUPT_INCORE);
|
1071 |
|
|
#ifdef DEBUG
|
1072 |
|
|
if (!(flags & XFS_TRANS_ABORT)) {
|
1073 |
|
|
licp = &(tp->t_items);
|
1074 |
|
|
while (licp != NULL) {
|
1075 |
|
|
lidp = licp->lic_descs;
|
1076 |
|
|
for (i = 0; i < licp->lic_unused; i++, lidp++) {
|
1077 |
|
|
if (XFS_LIC_ISFREE(licp, i)) {
|
1078 |
|
|
continue;
|
1079 |
|
|
}
|
1080 |
|
|
|
1081 |
|
|
lip = lidp->lid_item;
|
1082 |
|
|
if (!XFS_FORCED_SHUTDOWN(tp->t_mountp))
|
1083 |
|
|
ASSERT(!(lip->li_type == XFS_LI_EFD));
|
1084 |
|
|
}
|
1085 |
|
|
licp = licp->lic_next;
|
1086 |
|
|
}
|
1087 |
|
|
}
|
1088 |
|
|
#endif
|
1089 |
|
|
xfs_trans_unreserve_and_mod_sb(tp);
|
1090 |
|
|
XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(tp->t_mountp, tp);
|
1091 |
|
|
|
1092 |
|
|
if (tp->t_ticket) {
|
1093 |
|
|
if (flags & XFS_TRANS_RELEASE_LOG_RES) {
|
1094 |
|
|
ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
|
1095 |
|
|
log_flags = XFS_LOG_REL_PERM_RESERV;
|
1096 |
|
|
} else {
|
1097 |
|
|
log_flags = 0;
|
1098 |
|
|
}
|
1099 |
|
|
xfs_log_done(tp->t_mountp, tp->t_ticket, NULL, log_flags);
|
1100 |
|
|
}
|
1101 |
|
|
|
1102 |
|
|
/* mark this thread as no longer being in a transaction */
|
1103 |
|
|
PFLAGS_RESTORE(&tp->t_pflags);
|
1104 |
|
|
|
1105 |
|
|
xfs_trans_free_items(tp, flags);
|
1106 |
|
|
xfs_trans_free_busy(tp);
|
1107 |
|
|
xfs_trans_free(tp);
|
1108 |
|
|
}
|
1109 |
|
|
|
1110 |
|
|
|
1111 |
|
|
/*
|
1112 |
|
|
* Free the transaction structure. If there is more clean up
|
1113 |
|
|
* to do when the structure is freed, add it here.
|
1114 |
|
|
*/
|
1115 |
|
|
STATIC void
|
1116 |
|
|
xfs_trans_free(
|
1117 |
|
|
xfs_trans_t *tp)
|
1118 |
|
|
{
|
1119 |
|
|
atomic_dec(&tp->t_mountp->m_active_trans);
|
1120 |
|
|
XFS_TRANS_FREE_DQINFO(tp->t_mountp, tp);
|
1121 |
|
|
kmem_zone_free(xfs_trans_zone, tp);
|
1122 |
|
|
}
|
1123 |
|
|
|
1124 |
|
|
|
1125 |
|
|
/*
|
1126 |
|
|
* THIS SHOULD BE REWRITTEN TO USE xfs_trans_next_item().
|
1127 |
|
|
*
|
1128 |
|
|
* This is typically called by the LM when a transaction has been fully
|
1129 |
|
|
* committed to disk. It needs to unpin the items which have
|
1130 |
|
|
* been logged by the transaction and update their positions
|
1131 |
|
|
* in the AIL if necessary.
|
1132 |
|
|
* This also gets called when the transactions didn't get written out
|
1133 |
|
|
* because of an I/O error. Abortflag & XFS_LI_ABORTED is set then.
|
1134 |
|
|
*
|
1135 |
|
|
* Call xfs_trans_chunk_committed() to process the items in
|
1136 |
|
|
* each chunk.
|
1137 |
|
|
*/
|
1138 |
|
|
STATIC void
|
1139 |
|
|
xfs_trans_committed(
|
1140 |
|
|
xfs_trans_t *tp,
|
1141 |
|
|
int abortflag)
|
1142 |
|
|
{
|
1143 |
|
|
xfs_log_item_chunk_t *licp;
|
1144 |
|
|
xfs_log_item_chunk_t *next_licp;
|
1145 |
|
|
xfs_log_busy_chunk_t *lbcp;
|
1146 |
|
|
xfs_log_busy_slot_t *lbsp;
|
1147 |
|
|
int i;
|
1148 |
|
|
|
1149 |
|
|
/*
|
1150 |
|
|
* Call the transaction's completion callback if there
|
1151 |
|
|
* is one.
|
1152 |
|
|
*/
|
1153 |
|
|
if (tp->t_callback != NULL) {
|
1154 |
|
|
tp->t_callback(tp, tp->t_callarg);
|
1155 |
|
|
}
|
1156 |
|
|
|
1157 |
|
|
/*
|
1158 |
|
|
* Special case the chunk embedded in the transaction.
|
1159 |
|
|
*/
|
1160 |
|
|
licp = &(tp->t_items);
|
1161 |
|
|
if (!(XFS_LIC_ARE_ALL_FREE(licp))) {
|
1162 |
|
|
xfs_trans_chunk_committed(licp, tp->t_lsn, abortflag);
|
1163 |
|
|
}
|
1164 |
|
|
|
1165 |
|
|
/*
|
1166 |
|
|
* Process the items in each chunk in turn.
|
1167 |
|
|
*/
|
1168 |
|
|
licp = licp->lic_next;
|
1169 |
|
|
while (licp != NULL) {
|
1170 |
|
|
ASSERT(!XFS_LIC_ARE_ALL_FREE(licp));
|
1171 |
|
|
xfs_trans_chunk_committed(licp, tp->t_lsn, abortflag);
|
1172 |
|
|
next_licp = licp->lic_next;
|
1173 |
|
|
kmem_free(licp, sizeof(xfs_log_item_chunk_t));
|
1174 |
|
|
licp = next_licp;
|
1175 |
|
|
}
|
1176 |
|
|
|
1177 |
|
|
/*
|
1178 |
|
|
* Clear all the per-AG busy list items listed in this transaction
|
1179 |
|
|
*/
|
1180 |
|
|
lbcp = &tp->t_busy;
|
1181 |
|
|
while (lbcp != NULL) {
|
1182 |
|
|
for (i = 0, lbsp = lbcp->lbc_busy; i < lbcp->lbc_unused; i++, lbsp++) {
|
1183 |
|
|
if (!XFS_LBC_ISFREE(lbcp, i)) {
|
1184 |
|
|
xfs_alloc_clear_busy(tp, lbsp->lbc_ag,
|
1185 |
|
|
lbsp->lbc_idx);
|
1186 |
|
|
}
|
1187 |
|
|
}
|
1188 |
|
|
lbcp = lbcp->lbc_next;
|
1189 |
|
|
}
|
1190 |
|
|
xfs_trans_free_busy(tp);
|
1191 |
|
|
|
1192 |
|
|
/*
|
1193 |
|
|
* That's it for the transaction structure. Free it.
|
1194 |
|
|
*/
|
1195 |
|
|
xfs_trans_free(tp);
|
1196 |
|
|
}
|
1197 |
|
|
|
1198 |
|
|
/*
|
1199 |
|
|
* This is called to perform the commit processing for each
|
1200 |
|
|
* item described by the given chunk.
|
1201 |
|
|
*
|
1202 |
|
|
* The commit processing consists of unlocking items which were
|
1203 |
|
|
* held locked with the SYNC_UNLOCK attribute, calling the committed
|
1204 |
|
|
* routine of each logged item, updating the item's position in the AIL
|
1205 |
|
|
* if necessary, and unpinning each item. If the committed routine
|
1206 |
|
|
* returns -1, then do nothing further with the item because it
|
1207 |
|
|
* may have been freed.
|
1208 |
|
|
*
|
1209 |
|
|
* Since items are unlocked when they are copied to the incore
|
1210 |
|
|
* log, it is possible for two transactions to be completing
|
1211 |
|
|
* and manipulating the same item simultaneously. The AIL lock
|
1212 |
|
|
* will protect the lsn field of each item. The value of this
|
1213 |
|
|
* field can never go backwards.
|
1214 |
|
|
*
|
1215 |
|
|
* We unpin the items after repositioning them in the AIL, because
|
1216 |
|
|
* otherwise they could be immediately flushed and we'd have to race
|
1217 |
|
|
* with the flusher trying to pull the item from the AIL as we add it.
|
1218 |
|
|
*/
|
1219 |
|
|
STATIC void
|
1220 |
|
|
xfs_trans_chunk_committed(
|
1221 |
|
|
xfs_log_item_chunk_t *licp,
|
1222 |
|
|
xfs_lsn_t lsn,
|
1223 |
|
|
int aborted)
|
1224 |
|
|
{
|
1225 |
|
|
xfs_log_item_desc_t *lidp;
|
1226 |
|
|
xfs_log_item_t *lip;
|
1227 |
|
|
xfs_lsn_t item_lsn;
|
1228 |
|
|
struct xfs_mount *mp;
|
1229 |
|
|
int i;
|
1230 |
|
|
SPLDECL(s);
|
1231 |
|
|
|
1232 |
|
|
lidp = licp->lic_descs;
|
1233 |
|
|
for (i = 0; i < licp->lic_unused; i++, lidp++) {
|
1234 |
|
|
if (XFS_LIC_ISFREE(licp, i)) {
|
1235 |
|
|
continue;
|
1236 |
|
|
}
|
1237 |
|
|
|
1238 |
|
|
lip = lidp->lid_item;
|
1239 |
|
|
if (aborted)
|
1240 |
|
|
lip->li_flags |= XFS_LI_ABORTED;
|
1241 |
|
|
|
1242 |
|
|
if (lidp->lid_flags & XFS_LID_SYNC_UNLOCK) {
|
1243 |
|
|
IOP_UNLOCK(lip);
|
1244 |
|
|
}
|
1245 |
|
|
|
1246 |
|
|
/*
|
1247 |
|
|
* Send in the ABORTED flag to the COMMITTED routine
|
1248 |
|
|
* so that it knows whether the transaction was aborted
|
1249 |
|
|
* or not.
|
1250 |
|
|
*/
|
1251 |
|
|
item_lsn = IOP_COMMITTED(lip, lsn);
|
1252 |
|
|
|
1253 |
|
|
/*
|
1254 |
|
|
* If the committed routine returns -1, make
|
1255 |
|
|
* no more references to the item.
|
1256 |
|
|
*/
|
1257 |
|
|
if (XFS_LSN_CMP(item_lsn, (xfs_lsn_t)-1) == 0) {
|
1258 |
|
|
continue;
|
1259 |
|
|
}
|
1260 |
|
|
|
1261 |
|
|
/*
|
1262 |
|
|
* If the returned lsn is greater than what it
|
1263 |
|
|
* contained before, update the location of the
|
1264 |
|
|
* item in the AIL. If it is not, then do nothing.
|
1265 |
|
|
* Items can never move backwards in the AIL.
|
1266 |
|
|
*
|
1267 |
|
|
* While the new lsn should usually be greater, it
|
1268 |
|
|
* is possible that a later transaction completing
|
1269 |
|
|
* simultaneously with an earlier one using the
|
1270 |
|
|
* same item could complete first with a higher lsn.
|
1271 |
|
|
* This would cause the earlier transaction to fail
|
1272 |
|
|
* the test below.
|
1273 |
|
|
*/
|
1274 |
|
|
mp = lip->li_mountp;
|
1275 |
|
|
AIL_LOCK(mp,s);
|
1276 |
|
|
if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0) {
|
1277 |
|
|
/*
|
1278 |
|
|
* This will set the item's lsn to item_lsn
|
1279 |
|
|
* and update the position of the item in
|
1280 |
|
|
* the AIL.
|
1281 |
|
|
*
|
1282 |
|
|
* xfs_trans_update_ail() drops the AIL lock.
|
1283 |
|
|
*/
|
1284 |
|
|
xfs_trans_update_ail(mp, lip, item_lsn, s);
|
1285 |
|
|
} else {
|
1286 |
|
|
AIL_UNLOCK(mp, s);
|
1287 |
|
|
}
|
1288 |
|
|
|
1289 |
|
|
/*
|
1290 |
|
|
* Now that we've repositioned the item in the AIL,
|
1291 |
|
|
* unpin it so it can be flushed. Pass information
|
1292 |
|
|
* about buffer stale state down from the log item
|
1293 |
|
|
* flags, if anyone else stales the buffer we do not
|
1294 |
|
|
* want to pay any attention to it.
|
1295 |
|
|
*/
|
1296 |
|
|
IOP_UNPIN(lip, lidp->lid_flags & XFS_LID_BUF_STALE);
|
1297 |
|
|
}
|
1298 |
|
|
}
|