Blame view

fs/xfs/xfs_dfrag.c 9.16 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
28
29
  #include "xfs_dir2.h"
  #include "xfs_dmapi.h"
  #include "xfs_mount.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  #include "xfs_bmap_btree.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
31
  #include "xfs_alloc_btree.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  #include "xfs_ialloc_btree.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  #include "xfs_dir2_sf.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
34
  #include "xfs_attr_sf.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  #include "xfs_dinode.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  #include "xfs_inode.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
37
  #include "xfs_inode_item.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
  #include "xfs_bmap.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
39
  #include "xfs_btree.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
  #include "xfs_ialloc.h"
  #include "xfs_itable.h"
  #include "xfs_dfrag.h"
  #include "xfs_error.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  #include "xfs_rw.h"
739bfb2a7   Christoph Hellwig   [XFS] call common...
45
  #include "xfs_vnodeops.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
50
51
  
  /*
   * Syssgi interface for swapext
   */
  int
  xfs_swapext(
d0cfb3730   Eric Sandeen   [XFS] Stack footp...
52
  	xfs_swapext_t	__user *sxu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  {
d0cfb3730   Eric Sandeen   [XFS] Stack footp...
54
  	xfs_swapext_t	*sxp;
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
55
56
  	xfs_inode_t     *ip, *tip;
  	struct file	*file, *target_file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
  	int		error = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58

d0cfb3730   Eric Sandeen   [XFS] Stack footp...
59
  	sxp = kmem_alloc(sizeof(xfs_swapext_t), KM_MAYFAIL);
3e57ecf64   Olaf Weber   [XFS] Add paramet...
60
  	if (!sxp) {
d0cfb3730   Eric Sandeen   [XFS] Stack footp...
61
  		error = XFS_ERROR(ENOMEM);
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
62
  		goto out;
d0cfb3730   Eric Sandeen   [XFS] Stack footp...
63
64
65
66
  	}
  
  	if (copy_from_user(sxp, sxu, sizeof(xfs_swapext_t))) {
  		error = XFS_ERROR(EFAULT);
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
67
  		goto out_free_sxp;
d0cfb3730   Eric Sandeen   [XFS] Stack footp...
68
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
  
  	/* Pull information for the target fd */
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
71
72
  	file = fget((int)sxp->sx_fdtarget);
  	if (!file) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
  		error = XFS_ERROR(EINVAL);
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
74
  		goto out_free_sxp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  	}
f6aa7f218   Christoph Hellwig   [XFS] stop re-che...
76
77
78
79
  	if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND)) {
  		error = XFS_ERROR(EBADF);
  		goto out_put_file;
  	}
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
80
81
  	target_file = fget((int)sxp->sx_fdtmp);
  	if (!target_file) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  		error = XFS_ERROR(EINVAL);
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
83
  		goto out_put_file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  	}
f6aa7f218   Christoph Hellwig   [XFS] stop re-che...
85
86
87
88
89
  	if (!(target_file->f_mode & FMODE_WRITE) ||
  	    (target_file->f_flags & O_APPEND)) {
  		error = XFS_ERROR(EBADF);
  		goto out_put_target_file;
  	}
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
90
91
  	ip = XFS_I(file->f_path.dentry->d_inode);
  	tip = XFS_I(target_file->f_path.dentry->d_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
  
  	if (ip->i_mount != tip->i_mount) {
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
94
95
  		error = XFS_ERROR(EINVAL);
  		goto out_put_target_file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
98
  	}
  
  	if (ip->i_ino == tip->i_ino) {
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
99
100
  		error = XFS_ERROR(EINVAL);
  		goto out_put_target_file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
  	}
35fec8df6   Christoph Hellwig   [XFS] clean up xf...
102
103
104
  	if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
  		error = XFS_ERROR(EIO);
  		goto out_put_target_file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  	}
541d7d3c4   Lachlan McIlroy   [XFS] kill unness...
106
  	error = xfs_swap_extents(ip, tip, sxp);
3e57ecf64   Olaf Weber   [XFS] Add paramet...
107

35fec8df6   Christoph Hellwig   [XFS] clean up xf...
108
109
110
111
112
113
114
   out_put_target_file:
  	fput(target_file);
   out_put_file:
  	fput(file);
   out_free_sxp:
  	kmem_free(sxp, sizeof(xfs_swapext_t));
   out:
3e57ecf64   Olaf Weber   [XFS] Add paramet...
115
116
117
118
119
120
121
122
123
124
125
126
127
  	return error;
  }
  
  int
  xfs_swap_extents(
  	xfs_inode_t	*ip,
  	xfs_inode_t	*tip,
  	xfs_swapext_t	*sxp)
  {
  	xfs_mount_t	*mp;
  	xfs_inode_t	*ips[2];
  	xfs_trans_t	*tp;
  	xfs_bstat_t	*sbp = &sxp->sx_stat;
67fcaa73a   Nathan Scott   [XFS] Resolve a n...
128
  	bhv_vnode_t	*vp, *tvp;
3e57ecf64   Olaf Weber   [XFS] Add paramet...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  	xfs_ifork_t	*tempifp, *ifp, *tifp;
  	int		ilf_fields, tilf_fields;
  	static uint	lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL;
  	int		error = 0;
  	int		aforkblks = 0;
  	int		taforkblks = 0;
  	__uint64_t	tmp;
  	char		locked = 0;
  
  	mp = ip->i_mount;
  
  	tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL);
  	if (!tempifp) {
  		error = XFS_ERROR(ENOMEM);
  		goto error0;
  	}
  
  	sbp = &sxp->sx_stat;
  	vp = XFS_ITOV(ip);
  	tvp = XFS_ITOV(tip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
152
153
154
155
156
157
  
  	/* Lock in i_ino order */
  	if (ip->i_ino < tip->i_ino) {
  		ips[0] = ip;
  		ips[1] = tip;
  	} else {
  		ips[0] = tip;
  		ips[1] = ip;
  	}
d0cfb3730   Eric Sandeen   [XFS] Stack footp...
158

cfa853e47   Christoph Hellwig   [XFS] remove manu...
159
  	xfs_lock_inodes(ips, 2, lock_flags);
3e57ecf64   Olaf Weber   [XFS] Add paramet...
160
  	locked = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
164
165
166
167
168
  	/* 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);
  		goto error0;
  	}
  
  	/* Verify both files are either real-time or non-realtime */
71ddabb94   Eric Sandeen   [XFS] optimize XF...
169
  	if (XFS_IS_REALTIME_INODE(ip) != XFS_IS_REALTIME_INODE(tip)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
172
173
174
175
176
177
178
179
  		error = XFS_ERROR(EINVAL);
  		goto error0;
  	}
  
  	/* 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) {
  		error = XFS_ERROR(EINVAL);
  		goto error0;
  	}
bd5a876ac   Christoph Hellwig   [XFS] (mostly) re...
180
  	if (VN_CACHED(tvp) != 0) {
613d70436   Christoph Hellwig   [XFS] kill xfs_io...
181
  		xfs_inval_cached_trace(tip, 0, -1, 0, -1);
739bfb2a7   Christoph Hellwig   [XFS] call common...
182
183
  		error = xfs_flushinval_pages(tip, 0, -1,
  				FI_REMAPF_LOCKED);
d3cf20947   Lachlan McIlroy   [XFS] propogate r...
184
185
  		if (error)
  			goto error0;
bd5a876ac   Christoph Hellwig   [XFS] (mostly) re...
186
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
188
189
190
191
192
193
194
  
  	/* Verify O_DIRECT for ftmp */
  	if (VN_CACHED(tvp) != 0) {
  		error = XFS_ERROR(EINVAL);
  		goto error0;
  	}
  
  	/* Verify all data are being swapped */
d0cfb3730   Eric Sandeen   [XFS] Stack footp...
195
196
197
  	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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
  		error = XFS_ERROR(EFAULT);
  		goto error0;
  	}
  
  	/*
  	 * If the target has extended attributes, the tmp file
  	 * must also in order to ensure the correct data fork
  	 * format.
  	 */
  	if ( XFS_IFORK_Q(ip) != XFS_IFORK_Q(tip) ) {
  		error = XFS_ERROR(EINVAL);
  		goto error0;
  	}
  
  	/*
  	 * 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.
  	 */
  	if ((sbp->bs_ctime.tv_sec != ip->i_d.di_ctime.t_sec) ||
  	    (sbp->bs_ctime.tv_nsec != ip->i_d.di_ctime.t_nsec) ||
  	    (sbp->bs_mtime.tv_sec != ip->i_d.di_mtime.t_sec) ||
  	    (sbp->bs_mtime.tv_nsec != ip->i_d.di_mtime.t_nsec)) {
  		error = XFS_ERROR(EBUSY);
  		goto error0;
  	}
  
  	/* 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...
230
  	 * vop_read (or write in the case of autogrow) they block on the iolock
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
  	 * until we have switched the extents.
  	 */
  	if (VN_MAPPED(vp)) {
  		error = XFS_ERROR(EBUSY);
  		goto error0;
  	}
  
  	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...
248
  	xfs_tosspages(ip, 0, -1, FI_REMAPF);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
252
253
254
255
256
  
  	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);
d0cfb3730   Eric Sandeen   [XFS] Stack footp...
257
258
  		locked = 0;
  		goto error0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
  	}
cfa853e47   Christoph Hellwig   [XFS] remove manu...
260
  	xfs_lock_inodes(ips, 2, XFS_ILOCK_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
263
264
265
266
267
268
  
  	/*
  	 * 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);
  		if (error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
  			xfs_trans_cancel(tp, 0);
d0cfb3730   Eric Sandeen   [XFS] Stack footp...
270
  			goto error0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
275
276
277
  		}
  	}
  	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);
  		if (error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
  			xfs_trans_cancel(tp, 0);
d0cfb3730   Eric Sandeen   [XFS] Stack footp...
279
  			goto error0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
281
282
283
284
285
286
287
  		}
  	}
  
  	/*
  	 * Swap the data forks of the inodes
  	 */
  	ifp = &ip->i_df;
  	tifp = &tip->i_df;
d0cfb3730   Eric Sandeen   [XFS] Stack footp...
288
289
290
  	*tempifp = *ifp;	/* struct copy */
  	*ifp = *tifp;		/* struct copy */
  	*tifp = *tempifp;	/* struct copy */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
  
  	/*
  	 * 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;
  
  	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;
  	}
  
  	/*
  	 * Increment vnode ref counts since xfs_trans_commit &
  	 * xfs_trans_cancel will both unlock the inodes and
  	 * decrement the associated ref counts.
  	 */
  	VN_HOLD(vp);
  	VN_HOLD(tvp);
  
  	xfs_trans_ijoin(tp, ip, lock_flags);
  	xfs_trans_ijoin(tp, tip, lock_flags);
  
  	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.
  	 */
  	if (mp->m_flags & XFS_MOUNT_WSYNC) {
  		xfs_trans_set_sync(tp);
  	}
1c72bf900   Eric Sandeen   [XFS] The last ar...
366
  	error = xfs_trans_commit(tp, XFS_TRANS_SWAPEXT);
d0cfb3730   Eric Sandeen   [XFS] Stack footp...
367
  	locked = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
370
371
372
373
  
   error0:
  	if (locked) {
  		xfs_iunlock(ip,  lock_flags);
  		xfs_iunlock(tip, lock_flags);
  	}
d0cfb3730   Eric Sandeen   [XFS] Stack footp...
374
375
  	if (tempifp != NULL)
  		kmem_free(tempifp, sizeof(xfs_ifork_t));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
377
  	return error;
  }