Blame view

fs/xfs/xfs_dfrag.c 12.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
3e57ecf64   Olaf Weber   [XFS] Add paramet...
2
   * Copyright (c) 2000-2006 Silicon Graphics, Inc.
7b7187698   Nathan Scott   [XFS] Update lice...
3
   * All Rights Reserved.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
   *
7b7187698   Nathan Scott   [XFS] Update lice...
5
6
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License as
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
   * published by the Free Software Foundation.
   *
7b7187698   Nathan Scott   [XFS] Update lice...
9
10
11
12
   * This program is distributed in the hope that it would be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
   *
7b7187698   Nathan Scott   [XFS] Update lice...
14
15
16
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write the Free Software Foundation,
   * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
  #include "xfs.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
19
  #include "xfs_fs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
  #include "xfs_types.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
21
  #include "xfs_bit.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  #include "xfs_log.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
23
  #include "xfs_inum.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
  #include "xfs_trans.h"
  #include "xfs_sb.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
26
  #include "xfs_ag.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
  #include "xfs_mount.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  #include "xfs_bmap_btree.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  #include "xfs_dinode.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  #include "xfs_inode.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
31
  #include "xfs_inode_item.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  #include "xfs_bmap.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
35
  #include "xfs_itable.h"
  #include "xfs_dfrag.h"
  #include "xfs_error.h"
739bfb2a7   Christoph Hellwig   [XFS] call common...
36
  #include "xfs_vnodeops.h"
0b1b213fc   Christoph Hellwig   xfs: event tracin...
37
  #include "xfs_trace.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38

6bded0f38   Dave Chinner   xfs: clean up inc...
39
40
41
42
43
  
  static int xfs_swap_extents(
  	xfs_inode_t	*ip,	/* target inode */
  	xfs_inode_t	*tip,	/* tmp inode */
  	xfs_swapext_t	*sxp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  /*
6bded0f38   Dave Chinner   xfs: clean up inc...
45
   * ioctl interface for swapext
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
   */
  int
  xfs_swapext(
743bb4650   sandeen@sandeen.net   [XFS] Move copy_f...
49
  	xfs_swapext_t	*sxp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  {
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
51
  	xfs_inode_t     *ip, *tip;
6bded0f38   Dave Chinner   xfs: clean up inc...
52
  	struct file	*file, *tmp_file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  	int		error = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  	/* Pull information for the target fd */
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
56
57
  	file = fget((int)sxp->sx_fdtarget);
  	if (!file) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  		error = XFS_ERROR(EINVAL);
ac12b4e25   Eric Sandeen   don't reallocate ...
59
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
  	}
1817176a8   Dan Rosenberg   xfs: prevent swap...
61
62
63
  	if (!(file->f_mode & FMODE_WRITE) ||
  	    !(file->f_mode & FMODE_READ) ||
  	    (file->f_flags & O_APPEND)) {
f6aa7f218   Christoph Hellwig   [XFS] stop re-che...
64
65
66
  		error = XFS_ERROR(EBADF);
  		goto out_put_file;
  	}
6bded0f38   Dave Chinner   xfs: clean up inc...
67
68
  	tmp_file = fget((int)sxp->sx_fdtmp);
  	if (!tmp_file) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  		error = XFS_ERROR(EINVAL);
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
70
  		goto out_put_file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  	}
6bded0f38   Dave Chinner   xfs: clean up inc...
72
  	if (!(tmp_file->f_mode & FMODE_WRITE) ||
1817176a8   Dan Rosenberg   xfs: prevent swap...
73
  	    !(tmp_file->f_mode & FMODE_READ) ||
6bded0f38   Dave Chinner   xfs: clean up inc...
74
  	    (tmp_file->f_flags & O_APPEND)) {
f6aa7f218   Christoph Hellwig   [XFS] stop re-che...
75
  		error = XFS_ERROR(EBADF);
6bded0f38   Dave Chinner   xfs: clean up inc...
76
  		goto out_put_tmp_file;
f6aa7f218   Christoph Hellwig   [XFS] stop re-che...
77
  	}
7c8f7af67   Christoph Hellwig   xfs: reject swape...
78
  	if (IS_SWAPFILE(file->f_path.dentry->d_inode) ||
6bded0f38   Dave Chinner   xfs: clean up inc...
79
  	    IS_SWAPFILE(tmp_file->f_path.dentry->d_inode)) {
7c8f7af67   Christoph Hellwig   xfs: reject swape...
80
  		error = XFS_ERROR(EINVAL);
6bded0f38   Dave Chinner   xfs: clean up inc...
81
  		goto out_put_tmp_file;
7c8f7af67   Christoph Hellwig   xfs: reject swape...
82
  	}
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
83
  	ip = XFS_I(file->f_path.dentry->d_inode);
6bded0f38   Dave Chinner   xfs: clean up inc...
84
  	tip = XFS_I(tmp_file->f_path.dentry->d_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
  
  	if (ip->i_mount != tip->i_mount) {
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
87
  		error = XFS_ERROR(EINVAL);
6bded0f38   Dave Chinner   xfs: clean up inc...
88
  		goto out_put_tmp_file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
91
  	}
  
  	if (ip->i_ino == tip->i_ino) {
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
92
  		error = XFS_ERROR(EINVAL);
6bded0f38   Dave Chinner   xfs: clean up inc...
93
  		goto out_put_tmp_file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
  	}
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
95
96
  	if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
  		error = XFS_ERROR(EIO);
6bded0f38   Dave Chinner   xfs: clean up inc...
97
  		goto out_put_tmp_file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  	}
541d7d3c4   Lachlan McIlroy   [XFS] kill unness...
99
  	error = xfs_swap_extents(ip, tip, sxp);
3e57ecf64   Olaf Weber   [XFS] Add paramet...
100

6bded0f38   Dave Chinner   xfs: clean up inc...
101
102
   out_put_tmp_file:
  	fput(tmp_file);
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
103
104
   out_put_file:
  	fput(file);
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
105
   out:
3e57ecf64   Olaf Weber   [XFS] Add paramet...
106
107
  	return error;
  }
e09f98606   Dave Chinner   xfs: xfs_swap_ext...
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  /*
   * We need to check that the format of the data fork in the temporary inode is
   * valid for the target inode before doing the swap. This is not a problem with
   * attr1 because of the fixed fork offset, but attr2 has a dynamically sized
   * data fork depending on the space the attribute fork is taking so we can get
   * invalid formats on the target inode.
   *
   * E.g. target has space for 7 extents in extent format, temp inode only has
   * space for 6.  If we defragment down to 7 extents, then the tmp format is a
   * btree, but when swapped it needs to be in extent format. Hence we can't just
   * blindly swap data forks on attr2 filesystems.
   *
   * Note that we check the swap in both directions so that we don't end up with
   * a corrupt temporary inode, either.
   *
   * Note that fixing the way xfs_fsr sets up the attribute fork in the source
   * inode will prevent this situation from occurring, so all we do here is
   * reject and log the attempt. basically we are putting the responsibility on
   * userspace to get this right.
   */
  static int
  xfs_swap_extents_check_format(
  	xfs_inode_t	*ip,	/* target inode */
  	xfs_inode_t	*tip)	/* tmp inode */
  {
  
  	/* Should never get a local format */
  	if (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL ||
  	    tip->i_d.di_format == XFS_DINODE_FMT_LOCAL)
  		return EINVAL;
  
  	/*
  	 * if the target inode has less extents that then temporary inode then
  	 * why did userspace call us?
  	 */
  	if (ip->i_d.di_nextents < tip->i_d.di_nextents)
  		return EINVAL;
  
  	/*
  	 * if the target inode is in extent form and the temp inode is in btree
  	 * form then we will end up with the target inode in the wrong format
  	 * as we already know there are less extents in the temp inode.
  	 */
  	if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
  	    tip->i_d.di_format == XFS_DINODE_FMT_BTREE)
  		return EINVAL;
  
  	/* Check temp in extent form to max in target */
  	if (tip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
  	    XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) > ip->i_df.if_ext_max)
  		return EINVAL;
  
  	/* Check target in extent form to max in temp */
  	if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
  	    XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) > tip->i_df.if_ext_max)
  		return EINVAL;
dd77ef924   Dave Chinner   xfs: more swap ex...
164
165
166
167
168
169
170
171
172
  	/*
  	 * If we are in a btree format, check that the temp root block will fit
  	 * in the target and that it has enough extents to be in btree format
  	 * in the target.
  	 *
  	 * Note that we have to be careful to allow btree->extent conversions
  	 * (a common defrag case) which will occur when the temp inode is in
  	 * extent format...
  	 */
e09f98606   Dave Chinner   xfs: xfs_swap_ext...
173
  	if (tip->i_d.di_format == XFS_DINODE_FMT_BTREE &&
dd77ef924   Dave Chinner   xfs: more swap ex...
174
175
176
  	    ((XFS_IFORK_BOFF(ip) &&
  	      tip->i_df.if_broot_bytes > XFS_IFORK_BOFF(ip)) ||
  	     XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) <= ip->i_df.if_ext_max))
e09f98606   Dave Chinner   xfs: xfs_swap_ext...
177
  		return EINVAL;
dd77ef924   Dave Chinner   xfs: more swap ex...
178
  	/* Reciprocal target->temp btree format checks */
e09f98606   Dave Chinner   xfs: xfs_swap_ext...
179
  	if (ip->i_d.di_format == XFS_DINODE_FMT_BTREE &&
dd77ef924   Dave Chinner   xfs: more swap ex...
180
181
182
  	    ((XFS_IFORK_BOFF(tip) &&
  	      ip->i_df.if_broot_bytes > XFS_IFORK_BOFF(tip)) ||
  	     XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) <= tip->i_df.if_ext_max))
e09f98606   Dave Chinner   xfs: xfs_swap_ext...
183
184
185
186
  		return EINVAL;
  
  	return 0;
  }
6bded0f38   Dave Chinner   xfs: clean up inc...
187
  static int
3e57ecf64   Olaf Weber   [XFS] Add paramet...
188
  xfs_swap_extents(
e09f98606   Dave Chinner   xfs: xfs_swap_ext...
189
190
  	xfs_inode_t	*ip,	/* target inode */
  	xfs_inode_t	*tip,	/* tmp inode */
3e57ecf64   Olaf Weber   [XFS] Add paramet...
191
192
  	xfs_swapext_t	*sxp)
  {
45c51b999   David Sterba   xfs: cleanup dupl...
193
  	xfs_mount_t	*mp = ip->i_mount;
3e57ecf64   Olaf Weber   [XFS] Add paramet...
194
195
  	xfs_trans_t	*tp;
  	xfs_bstat_t	*sbp = &sxp->sx_stat;
3e57ecf64   Olaf Weber   [XFS] Add paramet...
196
197
  	xfs_ifork_t	*tempifp, *ifp, *tifp;
  	int		ilf_fields, tilf_fields;
3e57ecf64   Olaf Weber   [XFS] Add paramet...
198
199
200
201
  	int		error = 0;
  	int		aforkblks = 0;
  	int		taforkblks = 0;
  	__uint64_t	tmp;
3e57ecf64   Olaf Weber   [XFS] Add paramet...
202

3e57ecf64   Olaf Weber   [XFS] Add paramet...
203
204
205
  	tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL);
  	if (!tempifp) {
  		error = XFS_ERROR(ENOMEM);
ef8f7fc54   Josef 'Jeff' Sipek   xfs: cleanup erro...
206
  		goto out;
3e57ecf64   Olaf Weber   [XFS] Add paramet...
207
  	}
f9114eba1   David Chinner   [XFS] Prevent loc...
208
209
210
211
212
213
214
215
  	/*
  	 * we have to do two separate lock calls here to keep lockdep
  	 * happy. If we try to get all the locks in one call, lock will
  	 * report false positives when we drop the ILOCK and regain them
  	 * below.
  	 */
  	xfs_lock_two_inodes(ip, tip, XFS_IOLOCK_EXCL);
  	xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
219
  	/* Verify that both files have the same format */
  	if ((ip->i_d.di_mode & S_IFMT) != (tip->i_d.di_mode & S_IFMT)) {
  		error = XFS_ERROR(EINVAL);
ef8f7fc54   Josef 'Jeff' Sipek   xfs: cleanup erro...
220
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
223
  	}
  
  	/* Verify both files are either real-time or non-realtime */
71ddabb94   Eric Sandeen   [XFS] optimize XF...
224
  	if (XFS_IS_REALTIME_INODE(ip) != XFS_IS_REALTIME_INODE(tip)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  		error = XFS_ERROR(EINVAL);
ef8f7fc54   Josef 'Jeff' Sipek   xfs: cleanup erro...
226
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  	}
df80c933f   Christoph Hellwig   [XFS] remove some...
228
  	if (VN_CACHED(VFS_I(tip)) != 0) {
739bfb2a7   Christoph Hellwig   [XFS] call common...
229
230
  		error = xfs_flushinval_pages(tip, 0, -1,
  				FI_REMAPF_LOCKED);
d3cf20947   Lachlan McIlroy   [XFS] propogate r...
231
  		if (error)
ef8f7fc54   Josef 'Jeff' Sipek   xfs: cleanup erro...
232
  			goto out_unlock;
bd5a876ac   Christoph Hellwig   [XFS] (mostly) re...
233
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
  
  	/* Verify O_DIRECT for ftmp */
df80c933f   Christoph Hellwig   [XFS] remove some...
236
  	if (VN_CACHED(VFS_I(tip)) != 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
  		error = XFS_ERROR(EINVAL);
ef8f7fc54   Josef 'Jeff' Sipek   xfs: cleanup erro...
238
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
241
  	}
  
  	/* Verify all data are being swapped */
d0cfb3730   Eric Sandeen   [XFS] Stack footp...
242
243
244
  	if (sxp->sx_offset != 0 ||
  	    sxp->sx_length != ip->i_d.di_size ||
  	    sxp->sx_length != tip->i_d.di_size) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
  		error = XFS_ERROR(EFAULT);
ef8f7fc54   Josef 'Jeff' Sipek   xfs: cleanup erro...
246
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
  	}
3a85cd96d   Dave Chinner   xfs: add tracing ...
248
249
  	trace_xfs_swap_extent_before(ip, 0);
  	trace_xfs_swap_extent_before(tip, 1);
e09f98606   Dave Chinner   xfs: xfs_swap_ext...
250
251
252
  	/* check inode formats now that data is flushed */
  	error = xfs_swap_extents_check_format(ip, tip);
  	if (error) {
534877869   Dave Chinner   xfs: convert xfs_...
253
  		xfs_notice(mp,
e09f98606   Dave Chinner   xfs: xfs_swap_ext...
254
  		    "%s: inode 0x%llx format is incompatible for exchanging.",
534877869   Dave Chinner   xfs: convert xfs_...
255
  				__func__, ip->i_ino);
ef8f7fc54   Josef 'Jeff' Sipek   xfs: cleanup erro...
256
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
258
259
260
261
262
263
264
265
  	}
  
  	/*
  	 * Compare the current change & modify times with that
  	 * passed in.  If they differ, we abort this swap.
  	 * This is the mechanism used to ensure the calling
  	 * process that the file was not changed out from
  	 * under it.
  	 */
f9581b144   Christoph Hellwig   xfs: implement ->...
266
267
268
269
  	if ((sbp->bs_ctime.tv_sec != VFS_I(ip)->i_ctime.tv_sec) ||
  	    (sbp->bs_ctime.tv_nsec != VFS_I(ip)->i_ctime.tv_nsec) ||
  	    (sbp->bs_mtime.tv_sec != VFS_I(ip)->i_mtime.tv_sec) ||
  	    (sbp->bs_mtime.tv_nsec != VFS_I(ip)->i_mtime.tv_nsec)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
  		error = XFS_ERROR(EBUSY);
ef8f7fc54   Josef 'Jeff' Sipek   xfs: cleanup erro...
271
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
274
275
276
  	}
  
  	/* We need to fail if the file is memory mapped.  Once we have tossed
  	 * all existing pages, the page fault will have no option
  	 * but to go to the filesystem for pages. By making the page fault call
67fcaa73a   Nathan Scott   [XFS] Resolve a n...
277
  	 * vop_read (or write in the case of autogrow) they block on the iolock
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
279
  	 * until we have switched the extents.
  	 */
df80c933f   Christoph Hellwig   [XFS] remove some...
280
  	if (VN_MAPPED(VFS_I(ip))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
  		error = XFS_ERROR(EBUSY);
ef8f7fc54   Josef 'Jeff' Sipek   xfs: cleanup erro...
282
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
284
285
286
287
288
289
290
291
292
293
294
  	}
  
  	xfs_iunlock(ip, XFS_ILOCK_EXCL);
  	xfs_iunlock(tip, XFS_ILOCK_EXCL);
  
  	/*
  	 * There is a race condition here since we gave up the
  	 * ilock.  However, the data fork will not change since
  	 * we have the iolock (locked for truncation too) so we
  	 * are safe.  We don't really care if non-io related
  	 * fields change.
  	 */
739bfb2a7   Christoph Hellwig   [XFS] call common...
295
  	xfs_tosspages(ip, 0, -1, FI_REMAPF);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
299
300
301
302
303
  
  	tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT);
  	if ((error = xfs_trans_reserve(tp, 0,
  				     XFS_ICHANGE_LOG_RES(mp), 0,
  				     0, 0))) {
  		xfs_iunlock(ip,  XFS_IOLOCK_EXCL);
  		xfs_iunlock(tip, XFS_IOLOCK_EXCL);
  		xfs_trans_cancel(tp, 0);
ef8f7fc54   Josef 'Jeff' Sipek   xfs: cleanup erro...
304
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
  	}
e1cccd917   Christoph Hellwig   [XFS] kill xfs_lo...
306
  	xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
309
310
311
312
313
  
  	/*
  	 * Count the number of extended attribute blocks
  	 */
  	if ( ((XFS_IFORK_Q(ip) != 0) && (ip->i_d.di_anextents > 0)) &&
  	     (ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) {
  		error = xfs_bmap_count_blocks(tp, ip, XFS_ATTR_FORK, &aforkblks);
ef8f7fc54   Josef 'Jeff' Sipek   xfs: cleanup erro...
314
315
  		if (error)
  			goto out_trans_cancel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
318
319
320
  	}
  	if ( ((XFS_IFORK_Q(tip) != 0) && (tip->i_d.di_anextents > 0)) &&
  	     (tip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) {
  		error = xfs_bmap_count_blocks(tp, tip, XFS_ATTR_FORK,
  			&taforkblks);
ef8f7fc54   Josef 'Jeff' Sipek   xfs: cleanup erro...
321
322
  		if (error)
  			goto out_trans_cancel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
326
327
328
329
  	}
  
  	/*
  	 * Swap the data forks of the inodes
  	 */
  	ifp = &ip->i_df;
  	tifp = &tip->i_df;
d0cfb3730   Eric Sandeen   [XFS] Stack footp...
330
331
332
  	*tempifp = *ifp;	/* struct copy */
  	*ifp = *tifp;		/* struct copy */
  	*tifp = *tempifp;	/* struct copy */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
  
  	/*
e09f98606   Dave Chinner   xfs: xfs_swap_ext...
335
336
337
338
339
340
341
342
343
344
  	 * Fix the in-memory data fork values that are dependent on the fork
  	 * offset in the inode. We can't assume they remain the same as attr2
  	 * has dynamic fork offsets.
  	 */
  	ifp->if_ext_max = XFS_IFORK_SIZE(ip, XFS_DATA_FORK) /
  					(uint)sizeof(xfs_bmbt_rec_t);
  	tifp->if_ext_max = XFS_IFORK_SIZE(tip, XFS_DATA_FORK) /
  					(uint)sizeof(xfs_bmbt_rec_t);
  
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
346
347
348
349
350
351
352
353
354
355
356
357
  	 * Fix the on-disk inode values
  	 */
  	tmp = (__uint64_t)ip->i_d.di_nblocks;
  	ip->i_d.di_nblocks = tip->i_d.di_nblocks - taforkblks + aforkblks;
  	tip->i_d.di_nblocks = tmp + taforkblks - aforkblks;
  
  	tmp = (__uint64_t) ip->i_d.di_nextents;
  	ip->i_d.di_nextents = tip->i_d.di_nextents;
  	tip->i_d.di_nextents = tmp;
  
  	tmp = (__uint64_t) ip->i_d.di_format;
  	ip->i_d.di_format = tip->i_d.di_format;
  	tip->i_d.di_format = tmp;
309c84800   Dave Chinner   xfs: delayed allo...
358
359
360
361
362
363
364
365
366
367
368
369
  	/*
  	 * The extents in the source inode could still contain speculative
  	 * preallocation beyond EOF (e.g. the file is open but not modified
  	 * while defrag is in progress). In that case, we need to copy over the
  	 * number of delalloc blocks the data fork in the source inode is
  	 * tracking beyond EOF so that when the fork is truncated away when the
  	 * temporary inode is unlinked we don't underrun the i_delayed_blks
  	 * counter on that inode.
  	 */
  	ASSERT(tip->i_delayed_blks == 0);
  	tip->i_delayed_blks = ip->i_delayed_blks;
  	ip->i_delayed_blks = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
  	ilf_fields = XFS_ILOG_CORE;
  
  	switch(ip->i_d.di_format) {
  	case XFS_DINODE_FMT_EXTENTS:
  		/* If the extents fit in the inode, fix the
  		 * pointer.  Otherwise it's already NULL or
  		 * pointing to the extent.
  		 */
  		if (ip->i_d.di_nextents <= XFS_INLINE_EXTS) {
  			ifp->if_u1.if_extents =
  				ifp->if_u2.if_inline_ext;
  		}
  		ilf_fields |= XFS_ILOG_DEXT;
  		break;
  	case XFS_DINODE_FMT_BTREE:
  		ilf_fields |= XFS_ILOG_DBROOT;
  		break;
  	}
  
  	tilf_fields = XFS_ILOG_CORE;
  
  	switch(tip->i_d.di_format) {
  	case XFS_DINODE_FMT_EXTENTS:
  		/* If the extents fit in the inode, fix the
  		 * pointer.  Otherwise it's already NULL or
  		 * pointing to the extent.
  		 */
  		if (tip->i_d.di_nextents <= XFS_INLINE_EXTS) {
  			tifp->if_u1.if_extents =
  				tifp->if_u2.if_inline_ext;
  		}
  		tilf_fields |= XFS_ILOG_DEXT;
  		break;
  	case XFS_DINODE_FMT_BTREE:
  		tilf_fields |= XFS_ILOG_DBROOT;
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407

ddc3415ab   Christoph Hellwig   xfs: simplify xfs...
408
409
  	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
  	xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
411
412
413
414
415
416
417
  
  	xfs_trans_log_inode(tp, ip,  ilf_fields);
  	xfs_trans_log_inode(tp, tip, tilf_fields);
  
  	/*
  	 * If this is a synchronous mount, make sure that the
  	 * transaction goes to disk before returning to the user.
  	 */
ef8f7fc54   Josef 'Jeff' Sipek   xfs: cleanup erro...
418
  	if (mp->m_flags & XFS_MOUNT_WSYNC)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
  		xfs_trans_set_sync(tp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420

815cb2166   Christoph Hellwig   xfs: XFS_TRANS_SW...
421
  	error = xfs_trans_commit(tp, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422

3a85cd96d   Dave Chinner   xfs: add tracing ...
423
424
  	trace_xfs_swap_extent_after(ip, 0);
  	trace_xfs_swap_extent_after(tip, 1);
ef8f7fc54   Josef 'Jeff' Sipek   xfs: cleanup erro...
425
426
  out:
  	kmem_free(tempifp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
  	return error;
ef8f7fc54   Josef 'Jeff' Sipek   xfs: cleanup erro...
428

1f23920db   Felix Blyakher   xfs: fix double u...
429
430
431
432
  out_unlock:
  	xfs_iunlock(ip,  XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
  	xfs_iunlock(tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
  	goto out;
ef8f7fc54   Josef 'Jeff' Sipek   xfs: cleanup erro...
433
434
435
  out_trans_cancel:
  	xfs_trans_cancel(tp, 0);
  	goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
  }