Blame view

fs/xfs/xfs_vnodeops.c 69.9 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
   */
16f7e0fe2   Randy Dunlap   [PATCH] capable/c...
18

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
  #include "xfs.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
20
  #include "xfs_fs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  #include "xfs_types.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
22
  #include "xfs_bit.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
  #include "xfs_log.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
24
  #include "xfs_inum.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
  #include "xfs_trans.h"
  #include "xfs_sb.h"
  #include "xfs_ag.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  #include "xfs_dir2.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  #include "xfs_mount.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
30
  #include "xfs_da_btree.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
  #include "xfs_bmap_btree.h"
  #include "xfs_ialloc_btree.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  #include "xfs_dinode.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  #include "xfs_inode.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
35
  #include "xfs_inode_item.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
36
  #include "xfs_itable.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
37
38
  #include "xfs_ialloc.h"
  #include "xfs_alloc.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  #include "xfs_bmap.h"
ef14f0c15   Christoph Hellwig   xfs: use generic ...
40
  #include "xfs_acl.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
  #include "xfs_attr.h"
  #include "xfs_rw.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
  #include "xfs_error.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
  #include "xfs_quota.h"
  #include "xfs_utils.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
46
  #include "xfs_rtalloc.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  #include "xfs_trans_space.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
  #include "xfs_log_priv.h"
2a82b8be8   David Chinner   [XFS] Concurrent ...
49
  #include "xfs_filestream.h"
993386c19   Christoph Hellwig   [XFS] decontamina...
50
  #include "xfs_vnodeops.h"
0b1b213fc   Christoph Hellwig   xfs: event tracin...
51
  #include "xfs_trace.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

993386c19   Christoph Hellwig   [XFS] decontamina...
53
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  xfs_setattr(
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
55
56
  	struct xfs_inode	*ip,
  	struct iattr		*iattr,
ea5a3dc83   Christoph Hellwig   [XFS] kill sys_cred
57
  	int			flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  {
993386c19   Christoph Hellwig   [XFS] decontamina...
59
  	xfs_mount_t		*mp = ip->i_mount;
e4f752910   David Chinner   [XFS] Kill shouty...
60
  	struct inode		*inode = VFS_I(ip);
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
61
  	int			mask = iattr->ia_valid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
  	xfs_trans_t		*tp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
66
67
  	int			code;
  	uint			lock_flags;
  	uint			commit_flags=0;
  	uid_t			uid=0, iuid=0;
  	gid_t			gid=0, igid=0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
  	struct xfs_dquot	*udqp, *gdqp, *olddquot1, *olddquot2;
5fcbab355   Dean Roehrich   [XFS] Add ATTR_NO...
69
  	int			need_iolock = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70

cca28fb83   Christoph Hellwig   xfs: split xfs_it...
71
  	trace_xfs_setattr(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72

bd186aa90   Christoph Hellwig   [XFS] kill the vf...
73
  	if (mp->m_flags & XFS_MOUNT_RDONLY)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  		return XFS_ERROR(EROFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
  	if (XFS_FORCED_SHUTDOWN(mp))
  		return XFS_ERROR(EIO);
c4cd747ee   Christoph Hellwig   [XFS] use inode_c...
77
78
79
  	code = -inode_change_ok(inode, iattr);
  	if (code)
  		return code;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
81
82
83
84
85
86
87
88
89
90
  	olddquot1 = olddquot2 = NULL;
  	udqp = gdqp = NULL;
  
  	/*
  	 * If disk quotas is on, we make sure that the dquots do exist on disk,
  	 * before we start any other transactions. Trying to do this later
  	 * is messy. We don't care to take a readlock to look at the ids
  	 * in inode here, because we can't hold it across the trans_reserve.
  	 * If the IDs do change before we take the ilock, we're covered
  	 * because the i_*dquot fields will get updated anyway.
  	 */
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
91
  	if (XFS_IS_QUOTA_ON(mp) && (mask & (ATTR_UID|ATTR_GID))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
  		uint	qflags = 0;
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
93
94
  		if ((mask & ATTR_UID) && XFS_IS_UQUOTA_ON(mp)) {
  			uid = iattr->ia_uid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
98
  			qflags |= XFS_QMOPT_UQUOTA;
  		} else {
  			uid = ip->i_d.di_uid;
  		}
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
99
100
  		if ((mask & ATTR_GID) && XFS_IS_GQUOTA_ON(mp)) {
  			gid = iattr->ia_gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
104
  			qflags |= XFS_QMOPT_GQUOTA;
  		}  else {
  			gid = ip->i_d.di_gid;
  		}
25fe55e81   Christoph Hellwig   [XFS] xfs_setattr...
105

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
107
108
109
110
111
112
  		/*
  		 * We take a reference when we initialize udqp and gdqp,
  		 * so it is important that we never blindly double trip on
  		 * the same variable. See xfs_create() for an example.
  		 */
  		ASSERT(udqp == NULL);
  		ASSERT(gdqp == NULL);
6743099ce   Arkadiusz Mi?kiewicz   xfs: Extend proje...
113
  		code = xfs_qm_vop_dqalloc(ip, uid, gid, xfs_get_projid(ip),
25fe55e81   Christoph Hellwig   [XFS] xfs_setattr...
114
  					 qflags, &udqp, &gdqp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
  		if (code)
014c2544e   Jesper Juhl   return statement ...
116
  			return code;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
119
120
121
122
123
124
  	}
  
  	/*
  	 * For the other attributes, we acquire the inode lock and
  	 * first do an error checking pass.
  	 */
  	tp = NULL;
  	lock_flags = XFS_ILOCK_EXCL;
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
125
  	if (flags & XFS_ATTR_NOLOCK)
5fcbab355   Dean Roehrich   [XFS] Add ATTR_NO...
126
  		need_iolock = 0;
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
127
  	if (!(mask & ATTR_SIZE)) {
d6d59bada   Christoph Hellwig   xfs: fix timestam...
128
129
130
131
132
133
134
  		tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
  		commit_flags = 0;
  		code = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp),
  					 0, 0, 0);
  		if (code) {
  			lock_flags = 0;
  			goto error_return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
  		}
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
139
140
141
  		if (need_iolock)
  			lock_flags |= XFS_IOLOCK_EXCL;
  	}
  
  	xfs_ilock(ip, lock_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
  	/*
  	 * Change file ownership.  Must be the owner or privileged.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  	 */
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
145
  	if (mask & (ATTR_UID|ATTR_GID)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
148
149
150
151
152
  		/*
  		 * These IDs could have changed since we last looked at them.
  		 * But, we're assured that if the ownership did change
  		 * while we didn't have the inode locked, inode's dquot(s)
  		 * would have changed also.
  		 */
  		iuid = ip->i_d.di_uid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
  		igid = ip->i_d.di_gid;
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
154
155
  		gid = (mask & ATTR_GID) ? iattr->ia_gid : igid;
  		uid = (mask & ATTR_UID) ? iattr->ia_uid : iuid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
  
  		/*
25fe55e81   Christoph Hellwig   [XFS] xfs_setattr...
158
  		 * Do a quota reservation only if uid/gid is actually
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
  		 * going to change.
  		 */
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
161
162
163
  		if (XFS_IS_QUOTA_RUNNING(mp) &&
  		    ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) ||
  		     (XFS_IS_GQUOTA_ON(mp) && igid != gid))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
  			ASSERT(tp);
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
165
  			code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
167
168
169
170
171
172
173
174
175
  						capable(CAP_FOWNER) ?
  						XFS_QMOPT_FORCE_RES : 0);
  			if (code)	/* out of quota */
  				goto error_return;
  		}
  	}
  
  	/*
  	 * Truncate file.  Must have write permission and not be a directory.
  	 */
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
176
  	if (mask & ATTR_SIZE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  		/* Short circuit the truncate case for zero length files */
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
178
179
  		if (iattr->ia_size == 0 &&
  		    ip->i_size == 0 && ip->i_d.di_nextents == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
  			xfs_iunlock(ip, XFS_ILOCK_EXCL);
  			lock_flags &= ~XFS_ILOCK_EXCL;
dcd79a142   Dave Chinner   xfs: don't use vf...
182
183
184
185
186
  			if (mask & ATTR_CTIME) {
  				inode->i_mtime = inode->i_ctime =
  						current_fs_time(inode->i_sb);
  				xfs_mark_inode_dirty_sync(ip);
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
188
189
  			code = 0;
  			goto error_return;
  		}
42173f686   Christoph Hellwig   [XFS] Remove VN_I...
190
  		if (S_ISDIR(ip->i_d.di_mode)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
  			code = XFS_ERROR(EISDIR);
  			goto error_return;
42173f686   Christoph Hellwig   [XFS] Remove VN_I...
193
  		} else if (!S_ISREG(ip->i_d.di_mode)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
196
  			code = XFS_ERROR(EINVAL);
  			goto error_return;
  		}
c4cd747ee   Christoph Hellwig   [XFS] use inode_c...
197

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
  		/*
  		 * Make sure that the dquots are attached to the inode.
  		 */
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
201
  		code = xfs_qm_dqattach_locked(ip, 0);
c4cd747ee   Christoph Hellwig   [XFS] use inode_c...
202
  		if (code)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
  			goto error_return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204

c4cd747ee   Christoph Hellwig   [XFS] use inode_c...
205
206
207
208
209
210
211
212
  		/*
  		 * Now we can make the changes.  Before we join the inode
  		 * to the transaction, if ATTR_SIZE is set then take care of
  		 * the part of the truncation that must be done without the
  		 * inode lock.  This needs to be done before joining the inode
  		 * to the transaction, because the inode cannot be unlocked
  		 * once it is a part of the transaction.
  		 */
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
213
  		if (iattr->ia_size > ip->i_size) {
61436feba   Christoph Hellwig   [XFS] kill xfs_ig...
214
215
216
217
218
219
  			/*
  			 * Do the first part of growing a file: zero any data
  			 * in the last block that is beyond the old EOF.  We
  			 * need to do this before the inode is joined to the
  			 * transaction to modify the i_size.
  			 */
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
220
  			code = xfs_zero_eof(ip, iattr->ia_size, ip->i_size);
fa9b227e9   Christoph Hellwig   xfs: new truncate...
221
222
  			if (code)
  				goto error_return;
374e2ac33   Eric Sandeen   [XFS] Prevent dat...
223
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
  		xfs_iunlock(ip, XFS_ILOCK_EXCL);
fa9b227e9   Christoph Hellwig   xfs: new truncate...
225
  		lock_flags &= ~XFS_ILOCK_EXCL;
c32676eea   David Chinner   [XFS] Fix inode s...
226
227
228
229
230
231
232
233
234
235
236
237
238
  
  		/*
  		 * We are going to log the inode size change in this
  		 * transaction so any previous writes that are beyond the on
  		 * disk EOF and the new EOF that have not been written out need
  		 * to be written here. If we do not write the data out, we
  		 * expose ourselves to the null files problem.
  		 *
  		 * Only flush from the on disk size to the smaller of the in
  		 * memory file size or the new size as that's the range we
  		 * really care about here and prevents waiting for other data
  		 * not within the range we care about here.
  		 */
fa9b227e9   Christoph Hellwig   xfs: new truncate...
239
  		if (ip->i_size != ip->i_d.di_size &&
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
240
  		    iattr->ia_size > ip->i_d.di_size) {
739bfb2a7   Christoph Hellwig   [XFS] call common...
241
  			code = xfs_flush_pages(ip,
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
242
  					ip->i_d.di_size, iattr->ia_size,
0cadda1c5   Christoph Hellwig   xfs: remove dupli...
243
  					XBF_ASYNC, FI_NONE);
fa9b227e9   Christoph Hellwig   xfs: new truncate...
244
245
  			if (code)
  				goto error_return;
c32676eea   David Chinner   [XFS] Fix inode s...
246
247
248
  		}
  
  		/* wait for all I/O to complete */
25e41b3d5   Christoph Hellwig   move vn_iowait / ...
249
  		xfs_ioend_wait(ip);
c32676eea   David Chinner   [XFS] Fix inode s...
250

fa9b227e9   Christoph Hellwig   xfs: new truncate...
251
252
253
  		code = -block_truncate_page(inode->i_mapping, iattr->ia_size,
  					    xfs_get_blocks);
  		if (code)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  			goto error_return;
fa9b227e9   Christoph Hellwig   xfs: new truncate...
255

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
  		tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE);
fa9b227e9   Christoph Hellwig   xfs: new truncate...
257
258
259
260
261
262
263
  		code = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
  					 XFS_TRANS_PERM_LOG_RES,
  					 XFS_ITRUNCATE_LOG_COUNT);
  		if (code)
  			goto error_return;
  
  		truncate_setsize(inode, iattr->ia_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
  		commit_flags = XFS_TRANS_RELEASE_LOG_RES;
fa9b227e9   Christoph Hellwig   xfs: new truncate...
265
  		lock_flags |= XFS_ILOCK_EXCL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
  		xfs_ilock(ip, XFS_ILOCK_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267

898621d5a   Christoph Hellwig   xfs: simplify ino...
268
  		xfs_trans_ijoin(tp, ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269

44d814ced   David Chinner   [XFS] Update c/mt...
270
271
272
273
274
  		/*
  		 * Only change the c/mtime if we are changing the size
  		 * or we are explicitly asked to change it. This handles
  		 * the semantic difference between truncate() and ftruncate()
  		 * as implemented in the VFS.
d6d59bada   Christoph Hellwig   xfs: fix timestam...
275
276
277
278
279
280
  		 *
  		 * The regular truncate() case without ATTR_CTIME and ATTR_MTIME
  		 * is a special case where we need to update the times despite
  		 * not having these flags set.  For all other operations the
  		 * VFS set these flags explicitly if it wants a timestamp
  		 * update.
44d814ced   David Chinner   [XFS] Update c/mt...
281
  		 */
d6d59bada   Christoph Hellwig   xfs: fix timestam...
282
283
284
285
286
287
  		if (iattr->ia_size != ip->i_size &&
  		    (!(mask & (ATTR_CTIME | ATTR_MTIME)))) {
  			iattr->ia_ctime = iattr->ia_mtime =
  				current_fs_time(inode->i_sb);
  			mask |= ATTR_CTIME | ATTR_MTIME;
  		}
44d814ced   David Chinner   [XFS] Update c/mt...
288

0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
289
290
291
  		if (iattr->ia_size > ip->i_size) {
  			ip->i_d.di_size = iattr->ia_size;
  			ip->i_size = iattr->ia_size;
61436feba   Christoph Hellwig   [XFS] kill xfs_ig...
292
  			xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
293
294
  		} else if (iattr->ia_size <= ip->i_size ||
  			   (iattr->ia_size == 0 && ip->i_d.di_nextents)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
297
298
299
  			/*
  			 * signal a sync transaction unless
  			 * we're truncating an already unlinked
  			 * file on a wsync filesystem
  			 */
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
300
  			code = xfs_itruncate_finish(&tp, ip, iattr->ia_size,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
304
  					    XFS_DATA_FORK,
  					    ((ip->i_d.di_nlink != 0 ||
  					      !(mp->m_flags & XFS_MOUNT_WSYNC))
  					     ? 1 : 0));
7d4fb40ad   Nathan Scott   [XFS] Start write...
305
  			if (code)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
  				goto abort_return;
7d4fb40ad   Nathan Scott   [XFS] Start write...
307
308
309
310
311
312
313
314
  			/*
  			 * Truncated "down", so we're removing references
  			 * to old data here - if we now delay flushing for
  			 * a long time, we expose ourselves unduly to the
  			 * notorious NULL files problem.  So, we mark this
  			 * vnode and flush it when the file is closed, and
  			 * do not wait the usual (long) time for writeout.
  			 */
b3aea4edc   Christoph Hellwig   [XFS] kill the v_...
315
  			xfs_iflags_set(ip, XFS_ITRUNCATED);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
  		}
c4cd747ee   Christoph Hellwig   [XFS] use inode_c...
317
  	} else if (tp) {
898621d5a   Christoph Hellwig   xfs: simplify ino...
318
  		xfs_trans_ijoin(tp, ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
321
322
  	}
  
  	/*
  	 * Change file ownership.  Must be the owner or privileged.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
  	 */
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
324
  	if (mask & (ATTR_UID|ATTR_GID)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
  		/*
  		 * CAP_FSETID overrides the following restrictions:
  		 *
  		 * The set-user-ID and set-group-ID bits of a file will be
  		 * cleared upon successful return from chown()
  		 */
  		if ((ip->i_d.di_mode & (S_ISUID|S_ISGID)) &&
  		    !capable(CAP_FSETID)) {
  			ip->i_d.di_mode &= ~(S_ISUID|S_ISGID);
  		}
  
  		/*
  		 * Change the ownerships and register quota modifications
  		 * in the transaction.
  		 */
  		if (iuid != uid) {
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
341
  			if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_UQUOTA_ON(mp)) {
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
342
  				ASSERT(mask & ATTR_UID);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
  				ASSERT(udqp);
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
344
  				olddquot1 = xfs_qm_vop_chown(tp, ip,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
346
347
  							&ip->i_udquot, udqp);
  			}
  			ip->i_d.di_uid = uid;
f13fae2d2   Christoph Hellwig   [XFS] Remove vn_r...
348
  			inode->i_uid = uid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
  		}
  		if (igid != gid) {
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
351
  			if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_GQUOTA_ON(mp)) {
c8ad20ffe   Nathan Scott   [XFS] Add support...
352
  				ASSERT(!XFS_IS_PQUOTA_ON(mp));
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
353
  				ASSERT(mask & ATTR_GID);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
  				ASSERT(gdqp);
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
355
  				olddquot2 = xfs_qm_vop_chown(tp, ip,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
357
358
  							&ip->i_gdquot, gdqp);
  			}
  			ip->i_d.di_gid = gid;
f13fae2d2   Christoph Hellwig   [XFS] Remove vn_r...
359
  			inode->i_gid = gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
  	}
c4cd747ee   Christoph Hellwig   [XFS] use inode_c...
362
363
364
365
366
367
368
369
370
371
372
373
374
375
  	/*
  	 * Change file access modes.
  	 */
  	if (mask & ATTR_MODE) {
  		umode_t mode = iattr->ia_mode;
  
  		if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
  			mode &= ~S_ISGID;
  
  		ip->i_d.di_mode &= S_IFMT;
  		ip->i_d.di_mode |= mode & ~S_IFMT;
  
  		inode->i_mode &= S_IFMT;
  		inode->i_mode |= mode & ~S_IFMT;
c4cd747ee   Christoph Hellwig   [XFS] use inode_c...
376
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
379
380
  
  	/*
  	 * Change file access or modified times.
  	 */
d6d59bada   Christoph Hellwig   xfs: fix timestam...
381
382
383
384
385
  	if (mask & ATTR_ATIME) {
  		inode->i_atime = iattr->ia_atime;
  		ip->i_d.di_atime.t_sec = iattr->ia_atime.tv_sec;
  		ip->i_d.di_atime.t_nsec = iattr->ia_atime.tv_nsec;
  		ip->i_update_core = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
  	}
d6d59bada   Christoph Hellwig   xfs: fix timestam...
387
  	if (mask & ATTR_CTIME) {
f13fae2d2   Christoph Hellwig   [XFS] Remove vn_r...
388
  		inode->i_ctime = iattr->ia_ctime;
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
389
390
  		ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec;
  		ip->i_d.di_ctime.t_nsec = iattr->ia_ctime.tv_nsec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
  		ip->i_update_core = 1;
d6d59bada   Christoph Hellwig   xfs: fix timestam...
392
393
394
395
396
397
  	}
  	if (mask & ATTR_MTIME) {
  		inode->i_mtime = iattr->ia_mtime;
  		ip->i_d.di_mtime.t_sec = iattr->ia_mtime.tv_sec;
  		ip->i_d.di_mtime.t_nsec = iattr->ia_mtime.tv_nsec;
  		ip->i_update_core = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
399
400
  	}
  
  	/*
d6d59bada   Christoph Hellwig   xfs: fix timestam...
401
402
  	 * And finally, log the inode core if any attribute in it
  	 * has been changed.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
  	 */
d6d59bada   Christoph Hellwig   xfs: fix timestam...
404
405
406
  	if (mask & (ATTR_UID|ATTR_GID|ATTR_MODE|
  		    ATTR_ATIME|ATTR_CTIME|ATTR_MTIME))
  		xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
410
411
412
413
  
  	XFS_STATS_INC(xs_ig_attrchg);
  
  	/*
  	 * If this is a synchronous mount, make sure that the
  	 * transaction goes to disk before returning to the user.
  	 * This is slightly sub-optimal in that truncates require
c41564b5a   Nathan Scott   [XFS] We really s...
414
  	 * two sync transactions instead of one for wsync filesystems.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
417
418
419
420
  	 * One for the truncate and one for the timestamps since we
  	 * don't want to change the timestamps unless we're sure the
  	 * truncate worked.  Truncates are less than 1% of the laddis
  	 * mix so this probably isn't worth the trouble to optimize.
  	 */
  	code = 0;
d6d59bada   Christoph Hellwig   xfs: fix timestam...
421
422
  	if (mp->m_flags & XFS_MOUNT_WSYNC)
  		xfs_trans_set_sync(tp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423

d6d59bada   Christoph Hellwig   xfs: fix timestam...
424
  	code = xfs_trans_commit(tp, commit_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
427
428
429
430
  	xfs_iunlock(ip, lock_flags);
  
  	/*
  	 * Release any dquot(s) the inode had kept before chown.
  	 */
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
431
432
433
434
  	xfs_qm_dqrele(olddquot1);
  	xfs_qm_dqrele(olddquot2);
  	xfs_qm_dqrele(udqp);
  	xfs_qm_dqrele(gdqp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435

ef14f0c15   Christoph Hellwig   xfs: use generic ...
436
  	if (code)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
  		return code;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
438
439
440
441
442
443
444
445
446
447
448
449
  
  	/*
  	 * XXX(hch): Updating the ACL entries is not atomic vs the i_mode
  	 * 	     update.  We could avoid this with linked transactions
  	 * 	     and passing down the transaction pointer all the way
  	 *	     to attr_set.  No previous user of the generic
  	 * 	     Posix ACL code seems to care about this issue either.
  	 */
  	if ((mask & ATTR_MODE) && !(flags & XFS_ATTR_NOACL)) {
  		code = -xfs_acl_chmod(inode);
  		if (code)
  			return XFS_ERROR(code);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
452
453
454
  	return 0;
  
   abort_return:
  	commit_flags |= XFS_TRANS_ABORT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
   error_return:
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
456
457
  	xfs_qm_dqrele(udqp);
  	xfs_qm_dqrele(gdqp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
460
461
462
463
464
465
  	if (tp) {
  		xfs_trans_cancel(tp, commit_flags);
  	}
  	if (lock_flags != 0) {
  		xfs_iunlock(ip, lock_flags);
  	}
  	return code;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
  /*
7d4fb40ad   Nathan Scott   [XFS] Start write...
467
468
469
470
471
   * The maximum pathlen is 1024 bytes. Since the minimum file system
   * blocksize is 512 bytes, we can get a max of 2 extents back from
   * bmapi.
   */
  #define SYMLINK_MAPS 2
804c83c37   Christoph Hellwig   [XFS] stop using ...
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
  STATIC int
  xfs_readlink_bmap(
  	xfs_inode_t	*ip,
  	char		*link)
  {
  	xfs_mount_t	*mp = ip->i_mount;
  	int		pathlen = ip->i_d.di_size;
  	int             nmaps = SYMLINK_MAPS;
  	xfs_bmbt_irec_t mval[SYMLINK_MAPS];
  	xfs_daddr_t	d;
  	int		byte_cnt;
  	int		n;
  	xfs_buf_t	*bp;
  	int		error = 0;
  
  	error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), 0, NULL, 0,
b4e9181e7   Christoph Hellwig   xfs: remove unuse...
488
  			mval, &nmaps, NULL);
804c83c37   Christoph Hellwig   [XFS] stop using ...
489
490
491
492
493
494
  	if (error)
  		goto out;
  
  	for (n = 0; n < nmaps; n++) {
  		d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
  		byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
6ad112bfb   Christoph Hellwig   xfs: simplify xfs...
495
496
  		bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt),
  				  XBF_LOCK | XBF_MAPPED | XBF_DONT_BLOCK);
804c83c37   Christoph Hellwig   [XFS] stop using ...
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
  		error = XFS_BUF_GETERROR(bp);
  		if (error) {
  			xfs_ioerror_alert("xfs_readlink",
  				  ip->i_mount, bp, XFS_BUF_ADDR(bp));
  			xfs_buf_relse(bp);
  			goto out;
  		}
  		if (pathlen < byte_cnt)
  			byte_cnt = pathlen;
  		pathlen -= byte_cnt;
  
  		memcpy(link, XFS_BUF_PTR(bp), byte_cnt);
  		xfs_buf_relse(bp);
  	}
  
  	link[ip->i_d.di_size] = '\0';
  	error = 0;
  
   out:
  	return error;
  }
993386c19   Christoph Hellwig   [XFS] decontamina...
518
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
  xfs_readlink(
993386c19   Christoph Hellwig   [XFS] decontamina...
520
  	xfs_inode_t     *ip,
804c83c37   Christoph Hellwig   [XFS] stop using ...
521
  	char		*link)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
  {
804c83c37   Christoph Hellwig   [XFS] stop using ...
523
  	xfs_mount_t	*mp = ip->i_mount;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
  	int		pathlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
  	int		error = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526

cca28fb83   Christoph Hellwig   xfs: split xfs_it...
527
  	trace_xfs_readlink(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
529
530
531
532
533
534
  
  	if (XFS_FORCED_SHUTDOWN(mp))
  		return XFS_ERROR(EIO);
  
  	xfs_ilock(ip, XFS_ILOCK_SHARED);
  
  	ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFLNK);
804c83c37   Christoph Hellwig   [XFS] stop using ...
535
  	ASSERT(ip->i_d.di_size <= MAXPATHLEN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536

804c83c37   Christoph Hellwig   [XFS] stop using ...
537
538
539
  	pathlen = ip->i_d.di_size;
  	if (!pathlen)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
  
  	if (ip->i_df.if_flags & XFS_IFINLINE) {
804c83c37   Christoph Hellwig   [XFS] stop using ...
542
543
544
545
  		memcpy(link, ip->i_df.if_u1.if_data, pathlen);
  		link[pathlen] = '\0';
  	} else {
  		error = xfs_readlink_bmap(ip, link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
  	}
804c83c37   Christoph Hellwig   [XFS] stop using ...
547
   out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
  	xfs_iunlock(ip, XFS_ILOCK_SHARED);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
550
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
  /*
c56c9631c   Christoph Hellwig   xfs: fix mmap_sem...
552
553
554
555
556
   * Flags for xfs_free_eofblocks
   */
  #define XFS_FREE_EOF_TRYLOCK	(1<<0)
  
  /*
92dfe8d26   David Chinner   [XFS] Make hole p...
557
558
559
   * This is called by xfs_inactive to free any blocks beyond eof
   * when the link count isn't zero and by xfs_dm_punch_hole() when
   * punching a hole to EOF.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
   */
d96f8f891   Eric Sandeen   xfs: add more sta...
561
  STATIC int
92dfe8d26   David Chinner   [XFS] Make hole p...
562
  xfs_free_eofblocks(
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
  	xfs_mount_t	*mp,
92dfe8d26   David Chinner   [XFS] Make hole p...
564
565
  	xfs_inode_t	*ip,
  	int		flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
568
569
570
571
572
573
574
575
576
577
578
  {
  	xfs_trans_t	*tp;
  	int		error;
  	xfs_fileoff_t	end_fsb;
  	xfs_fileoff_t	last_fsb;
  	xfs_filblks_t	map_len;
  	int		nimaps;
  	xfs_bmbt_irec_t	imap;
  
  	/*
  	 * Figure out if there are any blocks beyond the end
  	 * of the file.  If not, then there is nothing to do.
  	 */
ba87ea699   Lachlan McIlroy   [XFS] Fix to prev...
579
  	end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)ip->i_size));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  	last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
3f34885cd   Kulikov Vasiliy   xfs: fix unsigned...
581
  	if (last_fsb <= end_fsb)
014c2544e   Jesper Juhl   return statement ...
582
  		return 0;
3f34885cd   Kulikov Vasiliy   xfs: fix unsigned...
583
  	map_len = last_fsb - end_fsb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584
585
586
  
  	nimaps = 1;
  	xfs_ilock(ip, XFS_ILOCK_SHARED);
541d7d3c4   Lachlan McIlroy   [XFS] kill unness...
587
  	error = xfs_bmapi(NULL, ip, end_fsb, map_len, 0,
b4e9181e7   Christoph Hellwig   xfs: remove unuse...
588
  			  NULL, 0, &imap, &nimaps, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
590
591
  	xfs_iunlock(ip, XFS_ILOCK_SHARED);
  
  	if (!error && (nimaps != 0) &&
68bdb6eab   Yingping Lu   [XFS] Fixed delay...
592
593
  	    (imap.br_startblock != HOLESTARTBLOCK ||
  	     ip->i_delayed_blks)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
596
  		/*
  		 * Attach the dquots to the inode up front.
  		 */
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
597
598
  		error = xfs_qm_dqattach(ip, 0);
  		if (error)
014c2544e   Jesper Juhl   return statement ...
599
  			return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
  
  		/*
  		 * There are blocks after the end of file.
  		 * Free them up now by truncating the file to
  		 * its current size.
  		 */
  		tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
  
  		/*
  		 * Do the xfs_itruncate_start() call before
  		 * reserving any log space because
  		 * itruncate_start will call into the buffer
  		 * cache and we can't
  		 * do that within a transaction.
  		 */
c56c9631c   Christoph Hellwig   xfs: fix mmap_sem...
615
616
617
618
619
620
  		if (flags & XFS_FREE_EOF_TRYLOCK) {
  			if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) {
  				xfs_trans_cancel(tp, 0);
  				return 0;
  			}
  		} else {
92dfe8d26   David Chinner   [XFS] Make hole p...
621
  			xfs_ilock(ip, XFS_IOLOCK_EXCL);
c56c9631c   Christoph Hellwig   xfs: fix mmap_sem...
622
  		}
d3cf20947   Lachlan McIlroy   [XFS] propogate r...
623
  		error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE,
ba87ea699   Lachlan McIlroy   [XFS] Fix to prev...
624
  				    ip->i_size);
d3cf20947   Lachlan McIlroy   [XFS] propogate r...
625
  		if (error) {
87ae3c241   Jesper Juhl   [XFS] Cancel tran...
626
  			xfs_trans_cancel(tp, 0);
c56c9631c   Christoph Hellwig   xfs: fix mmap_sem...
627
  			xfs_iunlock(ip, XFS_IOLOCK_EXCL);
d3cf20947   Lachlan McIlroy   [XFS] propogate r...
628
629
  			return error;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
632
633
634
635
636
637
638
  
  		error = xfs_trans_reserve(tp, 0,
  					  XFS_ITRUNCATE_LOG_RES(mp),
  					  0, XFS_TRANS_PERM_LOG_RES,
  					  XFS_ITRUNCATE_LOG_COUNT);
  		if (error) {
  			ASSERT(XFS_FORCED_SHUTDOWN(mp));
  			xfs_trans_cancel(tp, 0);
  			xfs_iunlock(ip, XFS_IOLOCK_EXCL);
014c2544e   Jesper Juhl   return statement ...
639
  			return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
641
642
  		}
  
  		xfs_ilock(ip, XFS_ILOCK_EXCL);
898621d5a   Christoph Hellwig   xfs: simplify ino...
643
  		xfs_trans_ijoin(tp, ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
  
  		error = xfs_itruncate_finish(&tp, ip,
ba87ea699   Lachlan McIlroy   [XFS] Fix to prev...
646
  					     ip->i_size,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
649
650
651
652
653
654
655
656
657
658
  					     XFS_DATA_FORK,
  					     0);
  		/*
  		 * If we get an error at this point we
  		 * simply don't bother truncating the file.
  		 */
  		if (error) {
  			xfs_trans_cancel(tp,
  					 (XFS_TRANS_RELEASE_LOG_RES |
  					  XFS_TRANS_ABORT));
  		} else {
  			error = xfs_trans_commit(tp,
1c72bf900   Eric Sandeen   [XFS] The last ar...
659
  						XFS_TRANS_RELEASE_LOG_RES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
  		}
c56c9631c   Christoph Hellwig   xfs: fix mmap_sem...
661
  		xfs_iunlock(ip, XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
  	}
014c2544e   Jesper Juhl   return statement ...
663
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
  }
  
  /*
   * Free a symlink that has blocks associated with it.
   */
  STATIC int
  xfs_inactive_symlink_rmt(
  	xfs_inode_t	*ip,
  	xfs_trans_t	**tpp)
  {
  	xfs_buf_t	*bp;
  	int		committed;
  	int		done;
  	int		error;
  	xfs_fsblock_t	first_block;
  	xfs_bmap_free_t	free_list;
  	int		i;
  	xfs_mount_t	*mp;
  	xfs_bmbt_irec_t	mval[SYMLINK_MAPS];
  	int		nmaps;
  	xfs_trans_t	*ntp;
  	int		size;
  	xfs_trans_t	*tp;
  
  	tp = *tpp;
  	mp = ip->i_mount;
  	ASSERT(ip->i_d.di_size > XFS_IFORK_DSIZE(ip));
  	/*
  	 * We're freeing a symlink that has some
  	 * blocks allocated to it.  Free the
  	 * blocks here.  We know that we've got
  	 * either 1 or 2 extents and that we can
  	 * free them all in one bunmapi call.
  	 */
  	ASSERT(ip->i_d.di_nextents > 0 && ip->i_d.di_nextents <= 2);
  	if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
  			XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) {
  		ASSERT(XFS_FORCED_SHUTDOWN(mp));
  		xfs_trans_cancel(tp, 0);
  		*tpp = NULL;
  		return error;
  	}
  	/*
  	 * Lock the inode, fix the size, and join it to the transaction.
  	 * Hold it so in the normal path, we still have it locked for
  	 * the second transaction.  In the error paths we need it
  	 * held so the cancel won't rele it, see below.
  	 */
  	xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
  	size = (int)ip->i_d.di_size;
  	ip->i_d.di_size = 0;
898621d5a   Christoph Hellwig   xfs: simplify ino...
715
  	xfs_trans_ijoin(tp, ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716
717
718
719
720
  	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
  	/*
  	 * Find the block(s) so we can inval and unmap them.
  	 */
  	done = 0;
9d87c3192   Eric Sandeen   [XFS] Remove the ...
721
  	xfs_bmap_init(&free_list, &first_block);
e8c96f8c2   Tobias Klauser   [PATCH] fs: Use A...
722
  	nmaps = ARRAY_SIZE(mval);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723
724
  	if ((error = xfs_bmapi(tp, ip, 0, XFS_B_TO_FSB(mp, size),
  			XFS_BMAPI_METADATA, &first_block, 0, mval, &nmaps,
b4e9181e7   Christoph Hellwig   xfs: remove unuse...
725
  			&free_list)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
727
728
729
730
731
732
733
734
735
736
737
738
739
  		goto error0;
  	/*
  	 * Invalidate the block(s).
  	 */
  	for (i = 0; i < nmaps; i++) {
  		bp = xfs_trans_get_buf(tp, mp->m_ddev_targp,
  			XFS_FSB_TO_DADDR(mp, mval[i].br_startblock),
  			XFS_FSB_TO_BB(mp, mval[i].br_blockcount), 0);
  		xfs_trans_binval(tp, bp);
  	}
  	/*
  	 * Unmap the dead block(s) to the free_list.
  	 */
  	if ((error = xfs_bunmapi(tp, ip, 0, size, XFS_BMAPI_METADATA, nmaps,
b4e9181e7   Christoph Hellwig   xfs: remove unuse...
740
  			&first_block, &free_list, &done)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
742
743
744
745
  		goto error1;
  	ASSERT(done);
  	/*
  	 * Commit the first transaction.  This logs the EFI and the inode.
  	 */
f7c99b6fc   Eric Sandeen   [XFS] Remove unus...
746
  	if ((error = xfs_bmap_finish(&tp, &free_list, &committed)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
749
750
751
752
753
754
755
756
757
758
  		goto error1;
  	/*
  	 * The transaction must have been committed, since there were
  	 * actually extents freed by xfs_bunmapi.  See xfs_bmap_finish.
  	 * The new tp has the extent freeing and EFDs.
  	 */
  	ASSERT(committed);
  	/*
  	 * The first xact was committed, so add the inode to the new one.
  	 * Mark it dirty so it will be logged and moved forward in the log as
  	 * part of every commit.
  	 */
898621d5a   Christoph Hellwig   xfs: simplify ino...
759
  	xfs_trans_ijoin(tp, ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
761
762
763
764
765
  	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
  	/*
  	 * Get a new, empty transaction to return to our caller.
  	 */
  	ntp = xfs_trans_dup(tp);
  	/*
c41564b5a   Nathan Scott   [XFS] We really s...
766
  	 * Commit the transaction containing extent freeing and EFDs.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
769
770
  	 * If we get an error on the commit here or on the reserve below,
  	 * we need to unlock the inode since the new transaction doesn't
  	 * have the inode attached.
  	 */
1c72bf900   Eric Sandeen   [XFS] The last ar...
771
  	error = xfs_trans_commit(tp, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
773
774
775
776
777
  	tp = ntp;
  	if (error) {
  		ASSERT(XFS_FORCED_SHUTDOWN(mp));
  		goto error0;
  	}
  	/*
cc09c0dc5   Dave Chinner   [XFS] Fix double ...
778
779
780
781
782
783
  	 * transaction commit worked ok so we can drop the extra ticket
  	 * reference that we gained in xfs_trans_dup()
  	 */
  	xfs_log_ticket_put(tp->t_ticket);
  
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
  	 * Remove the memory for extent descriptions (just bookkeeping).
  	 */
  	if (ip->i_df.if_bytes)
  		xfs_idata_realloc(ip, -ip->i_df.if_bytes, XFS_DATA_FORK);
  	ASSERT(ip->i_df.if_bytes == 0);
  	/*
  	 * Put an itruncate log reservation in the new transaction
  	 * for our caller.
  	 */
  	if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
  			XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) {
  		ASSERT(XFS_FORCED_SHUTDOWN(mp));
  		goto error0;
  	}
  	/*
  	 * Return with the inode locked but not joined to the transaction.
  	 */
  	*tpp = tp;
  	return 0;
  
   error1:
  	xfs_bmap_cancel(&free_list);
   error0:
  	/*
  	 * Have to come here with the inode locked and either
  	 * (held and in the transaction) or (not in the transaction).
  	 * If the inode isn't held then cancel would iput it, but
  	 * that's wrong since this is inactive and the vnode ref
  	 * count is 0 already.
  	 * Cancel won't do anything to the inode if held, but it still
  	 * needs to be locked until the cancel is done, if it was
  	 * joined to the transaction.
  	 */
  	xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
  	xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
  	*tpp = NULL;
  	return error;
  
  }
  
  STATIC int
  xfs_inactive_symlink_local(
  	xfs_inode_t	*ip,
  	xfs_trans_t	**tpp)
  {
  	int		error;
  
  	ASSERT(ip->i_d.di_size <= XFS_IFORK_DSIZE(ip));
  	/*
  	 * We're freeing a symlink which fit into
  	 * the inode.  Just free the memory used
  	 * to hold the old symlink.
  	 */
  	error = xfs_trans_reserve(*tpp, 0,
  				  XFS_ITRUNCATE_LOG_RES(ip->i_mount),
  				  0, XFS_TRANS_PERM_LOG_RES,
  				  XFS_ITRUNCATE_LOG_COUNT);
  
  	if (error) {
  		xfs_trans_cancel(*tpp, 0);
  		*tpp = NULL;
014c2544e   Jesper Juhl   return statement ...
845
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846
847
848
849
850
851
852
853
854
855
856
857
  	}
  	xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
  
  	/*
  	 * Zero length symlinks _can_ exist.
  	 */
  	if (ip->i_df.if_bytes > 0) {
  		xfs_idata_realloc(ip,
  				  -(ip->i_df.if_bytes),
  				  XFS_DATA_FORK);
  		ASSERT(ip->i_df.if_bytes == 0);
  	}
014c2544e   Jesper Juhl   return statement ...
858
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
861
862
863
864
865
866
867
  STATIC int
  xfs_inactive_attrs(
  	xfs_inode_t	*ip,
  	xfs_trans_t	**tpp)
  {
  	xfs_trans_t	*tp;
  	int		error;
  	xfs_mount_t	*mp;
579aa9caf   Christoph Hellwig   [XFS] shrink mrlo...
868
  	ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
870
871
  	tp = *tpp;
  	mp = ip->i_mount;
  	ASSERT(ip->i_d.di_forkoff != 0);
e5720eec0   David Chinner   [XFS] Propagate e...
872
  	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873
  	xfs_iunlock(ip, XFS_ILOCK_EXCL);
e5720eec0   David Chinner   [XFS] Propagate e...
874
875
  	if (error)
  		goto error_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
877
  
  	error = xfs_attr_inactive(ip);
e5720eec0   David Chinner   [XFS] Propagate e...
878
879
  	if (error)
  		goto error_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
880
881
882
883
884
885
  
  	tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
  	error = xfs_trans_reserve(tp, 0,
  				  XFS_IFREE_LOG_RES(mp),
  				  0, XFS_TRANS_PERM_LOG_RES,
  				  XFS_INACTIVE_LOG_COUNT);
e5720eec0   David Chinner   [XFS] Propagate e...
886
887
  	if (error)
  		goto error_cancel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
889
  
  	xfs_ilock(ip, XFS_ILOCK_EXCL);
898621d5a   Christoph Hellwig   xfs: simplify ino...
890
  	xfs_trans_ijoin(tp, ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
891
892
893
894
895
  	xfs_idestroy_fork(ip, XFS_ATTR_FORK);
  
  	ASSERT(ip->i_d.di_anextents == 0);
  
  	*tpp = tp;
014c2544e   Jesper Juhl   return statement ...
896
  	return 0;
e5720eec0   David Chinner   [XFS] Propagate e...
897
898
899
900
901
902
903
904
  
  error_cancel:
  	ASSERT(XFS_FORCED_SHUTDOWN(mp));
  	xfs_trans_cancel(tp, 0);
  error_unlock:
  	*tpp = NULL;
  	xfs_iunlock(ip, XFS_IOLOCK_EXCL);
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
  }
993386c19   Christoph Hellwig   [XFS] decontamina...
906
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
907
  xfs_release(
993386c19   Christoph Hellwig   [XFS] decontamina...
908
  	xfs_inode_t	*ip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
  {
993386c19   Christoph Hellwig   [XFS] decontamina...
910
  	xfs_mount_t	*mp = ip->i_mount;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
  	int		error;
42173f686   Christoph Hellwig   [XFS] Remove VN_I...
912
  	if (!S_ISREG(ip->i_d.di_mode) || (ip->i_d.di_mode == 0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
915
  
  	/* If this is a read-only mount, don't do this (would generate I/O) */
bd186aa90   Christoph Hellwig   [XFS] kill the vf...
916
  	if (mp->m_flags & XFS_MOUNT_RDONLY)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
  		return 0;
2a82b8be8   David Chinner   [XFS] Concurrent ...
918
  	if (!XFS_FORCED_SHUTDOWN(mp)) {
b3aea4edc   Christoph Hellwig   [XFS] kill the v_...
919
  		int truncated;
2a82b8be8   David Chinner   [XFS] Concurrent ...
920
921
922
923
924
925
926
927
928
  		/*
  		 * If we are using filestreams, and we have an unlinked
  		 * file that we are processing the last close on, then nothing
  		 * will be able to reopen and write to this file. Purge this
  		 * inode from the filestreams cache so that it doesn't delay
  		 * teardown of the inode.
  		 */
  		if ((ip->i_d.di_nlink == 0) && xfs_inode_is_filestream(ip))
  			xfs_filestream_deassociate(ip);
fbf3ce8d8   Christoph Hellwig   [XFS] XFS should ...
929
930
931
932
933
934
935
936
937
938
  		/*
  		 * If we previously truncated this file and removed old data
  		 * in the process, we want to initiate "early" writeout on
  		 * the last close.  This is an attempt to combat the notorious
  		 * NULL files problem which is particularly noticable from a
  		 * truncate down, buffered (re-)write (delalloc), followed by
  		 * a crash.  What we are effectively doing here is
  		 * significantly reducing the time window where we'd otherwise
  		 * be exposed to that problem.
  		 */
09262b433   Christoph Hellwig   [XFS] Create xfs_...
939
  		truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED);
df80c933f   Christoph Hellwig   [XFS] remove some...
940
  		if (truncated && VN_DIRTY(VFS_I(ip)) && ip->i_delayed_blks > 0)
0cadda1c5   Christoph Hellwig   xfs: remove dupli...
941
  			xfs_flush_pages(ip, 0, -1, XBF_ASYNC, FI_NONE);
fbf3ce8d8   Christoph Hellwig   [XFS] XFS should ...
942
  	}
6e857567d   Dave Chinner   xfs: don't trunca...
943
944
  	if (ip->i_d.di_nlink == 0)
  		return 0;
c56c9631c   Christoph Hellwig   xfs: fix mmap_sem...
945

6e857567d   Dave Chinner   xfs: don't trunca...
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
  	if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) &&
  	     ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 ||
  	       ip->i_delayed_blks > 0)) &&
  	     (ip->i_df.if_flags & XFS_IFEXTENTS))  &&
  	    (!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) {
  
  		/*
  		 * If we can't get the iolock just skip truncating the blocks
  		 * past EOF because we could deadlock with the mmap_sem
  		 * otherwise.  We'll get another chance to drop them once the
  		 * last reference to the inode is dropped, so we'll never leak
  		 * blocks permanently.
  		 *
  		 * Further, check if the inode is being opened, written and
  		 * closed frequently and we have delayed allocation blocks
  		 * oustanding (e.g. streaming writes from the NFS server),
  		 * truncating the blocks past EOF will cause fragmentation to
  		 * occur.
  		 *
  		 * In this case don't do the truncation, either, but we have to
  		 * be careful how we detect this case. Blocks beyond EOF show
  		 * up as i_delayed_blks even when the inode is clean, so we
  		 * need to truncate them away first before checking for a dirty
  		 * release. Hence on the first dirty close we will still remove
  		 * the speculative allocation, but after that we will leave it
  		 * in place.
  		 */
  		if (xfs_iflags_test(ip, XFS_IDIRTY_RELEASE))
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975

6e857567d   Dave Chinner   xfs: don't trunca...
976
977
978
979
980
981
982
983
984
  		error = xfs_free_eofblocks(mp, ip,
  					   XFS_FREE_EOF_TRYLOCK);
  		if (error)
  			return error;
  
  		/* delalloc blocks after truncation means it really is dirty */
  		if (ip->i_delayed_blks)
  			xfs_iflags_set(ip, XFS_IDIRTY_RELEASE);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
985
986
987
988
989
990
991
992
993
994
995
  	return 0;
  }
  
  /*
   * xfs_inactive
   *
   * This is called when the vnode reference count for the vnode
   * goes to zero.  If the file has been unlinked, then it must
   * now be truncated.  Also, we clear all of the read-ahead state
   * kept for the inode here since the file is now closed.
   */
993386c19   Christoph Hellwig   [XFS] decontamina...
996
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997
  xfs_inactive(
993386c19   Christoph Hellwig   [XFS] decontamina...
998
  	xfs_inode_t	*ip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
999
  {
67fcaa73a   Nathan Scott   [XFS] Resolve a n...
1000
  	xfs_bmap_free_t	free_list;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1001
1002
1003
1004
1005
1006
  	xfs_fsblock_t	first_block;
  	int		committed;
  	xfs_trans_t	*tp;
  	xfs_mount_t	*mp;
  	int		error;
  	int		truncate;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
1008
1009
1010
  	/*
  	 * If the inode is already free, then there can be nothing
  	 * to clean up here.
  	 */
cb4c8cc1e   Christoph Hellwig   xfs: kill VN_BAD
1011
  	if (ip->i_d.di_mode == 0 || is_bad_inode(VFS_I(ip))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
  		ASSERT(ip->i_df.if_real_bytes == 0);
  		ASSERT(ip->i_df.if_broot_bytes == 0);
  		return VN_INACTIVE_CACHE;
  	}
  
  	/*
  	 * Only do a truncate if it's a regular file with
  	 * some actual space in it.  It's OK to look at the
  	 * inode's fields without the lock because we're the
  	 * only one with a reference to the inode.
  	 */
  	truncate = ((ip->i_d.di_nlink == 0) &&
ba87ea699   Lachlan McIlroy   [XFS] Fix to prev...
1024
1025
  	    ((ip->i_d.di_size != 0) || (ip->i_size != 0) ||
  	     (ip->i_d.di_nextents > 0) || (ip->i_delayed_blks > 0)) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1026
1027
1028
  	    ((ip->i_d.di_mode & S_IFMT) == S_IFREG));
  
  	mp = ip->i_mount;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1029
1030
1031
  	error = 0;
  
  	/* If this is a read-only mount, don't do this (would generate I/O) */
bd186aa90   Christoph Hellwig   [XFS] kill the vf...
1032
  	if (mp->m_flags & XFS_MOUNT_RDONLY)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
1034
1035
1036
  		goto out;
  
  	if (ip->i_d.di_nlink != 0) {
  		if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) &&
df80c933f   Christoph Hellwig   [XFS] remove some...
1037
                       ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 ||
68bdb6eab   Yingping Lu   [XFS] Fixed delay...
1038
                         ip->i_delayed_blks > 0)) &&
dd9f438e3   Nathan Scott   [XFS] Implement t...
1039
1040
1041
1042
  		      (ip->i_df.if_flags & XFS_IFEXTENTS) &&
  		     (!(ip->i_d.di_flags &
  				(XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) ||
  		      (ip->i_delayed_blks != 0)))) {
c56c9631c   Christoph Hellwig   xfs: fix mmap_sem...
1043
  			error = xfs_free_eofblocks(mp, ip, 0);
92dfe8d26   David Chinner   [XFS] Make hole p...
1044
  			if (error)
014c2544e   Jesper Juhl   return statement ...
1045
  				return VN_INACTIVE_CACHE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046
1047
1048
1049
1050
  		}
  		goto out;
  	}
  
  	ASSERT(ip->i_d.di_nlink == 0);
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
1051
1052
  	error = xfs_qm_dqattach(ip, 0);
  	if (error)
014c2544e   Jesper Juhl   return statement ...
1053
  		return VN_INACTIVE_CACHE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
  
  	tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
  	if (truncate) {
  		/*
  		 * Do the xfs_itruncate_start() call before
  		 * reserving any log space because itruncate_start
  		 * will call into the buffer cache and we can't
  		 * do that within a transaction.
  		 */
  		xfs_ilock(ip, XFS_IOLOCK_EXCL);
d3cf20947   Lachlan McIlroy   [XFS] propogate r...
1064
1065
  		error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0);
  		if (error) {
87ae3c241   Jesper Juhl   [XFS] Cancel tran...
1066
  			xfs_trans_cancel(tp, 0);
d3cf20947   Lachlan McIlroy   [XFS] propogate r...
1067
1068
1069
  			xfs_iunlock(ip, XFS_IOLOCK_EXCL);
  			return VN_INACTIVE_CACHE;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
  
  		error = xfs_trans_reserve(tp, 0,
  					  XFS_ITRUNCATE_LOG_RES(mp),
  					  0, XFS_TRANS_PERM_LOG_RES,
  					  XFS_ITRUNCATE_LOG_COUNT);
  		if (error) {
  			/* Don't call itruncate_cleanup */
  			ASSERT(XFS_FORCED_SHUTDOWN(mp));
  			xfs_trans_cancel(tp, 0);
  			xfs_iunlock(ip, XFS_IOLOCK_EXCL);
014c2544e   Jesper Juhl   return statement ...
1080
  			return VN_INACTIVE_CACHE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081
1082
1083
  		}
  
  		xfs_ilock(ip, XFS_ILOCK_EXCL);
898621d5a   Christoph Hellwig   xfs: simplify ino...
1084
  		xfs_trans_ijoin(tp, ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
  
  		/*
  		 * normally, we have to run xfs_itruncate_finish sync.
  		 * But if filesystem is wsync and we're in the inactive
  		 * path, then we know that nlink == 0, and that the
  		 * xaction that made nlink == 0 is permanently committed
  		 * since xfs_remove runs as a synchronous transaction.
  		 */
  		error = xfs_itruncate_finish(&tp, ip, 0, XFS_DATA_FORK,
  				(!(mp->m_flags & XFS_MOUNT_WSYNC) ? 1 : 0));
  
  		if (error) {
  			xfs_trans_cancel(tp,
  				XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
  			xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
014c2544e   Jesper Juhl   return statement ...
1100
  			return VN_INACTIVE_CACHE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
  		}
  	} else if ((ip->i_d.di_mode & S_IFMT) == S_IFLNK) {
  
  		/*
  		 * If we get an error while cleaning up a
  		 * symlink we bail out.
  		 */
  		error = (ip->i_d.di_size > XFS_IFORK_DSIZE(ip)) ?
  			xfs_inactive_symlink_rmt(ip, &tp) :
  			xfs_inactive_symlink_local(ip, &tp);
  
  		if (error) {
  			ASSERT(tp == NULL);
014c2544e   Jesper Juhl   return statement ...
1114
  			return VN_INACTIVE_CACHE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1115
  		}
898621d5a   Christoph Hellwig   xfs: simplify ino...
1116
  		xfs_trans_ijoin(tp, ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117
1118
1119
1120
1121
1122
1123
1124
  	} else {
  		error = xfs_trans_reserve(tp, 0,
  					  XFS_IFREE_LOG_RES(mp),
  					  0, XFS_TRANS_PERM_LOG_RES,
  					  XFS_INACTIVE_LOG_COUNT);
  		if (error) {
  			ASSERT(XFS_FORCED_SHUTDOWN(mp));
  			xfs_trans_cancel(tp, 0);
014c2544e   Jesper Juhl   return statement ...
1125
  			return VN_INACTIVE_CACHE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126
1127
1128
  		}
  
  		xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
898621d5a   Christoph Hellwig   xfs: simplify ino...
1129
  		xfs_trans_ijoin(tp, ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
  	}
  
  	/*
  	 * If there are attributes associated with the file
  	 * then blow them away now.  The code calls a routine
  	 * that recursively deconstructs the attribute fork.
  	 * We need to just commit the current transaction
  	 * because we can't use it for xfs_attr_inactive().
  	 */
  	if (ip->i_d.di_anextents > 0) {
  		error = xfs_inactive_attrs(ip, &tp);
  		/*
  		 * If we got an error, the transaction is already
  		 * cancelled, and the inode is unlocked. Just get out.
  		 */
  		 if (error)
014c2544e   Jesper Juhl   return statement ...
1146
  			 return VN_INACTIVE_CACHE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147
1148
1149
1150
1151
1152
1153
  	} else if (ip->i_afp) {
  		xfs_idestroy_fork(ip, XFS_ATTR_FORK);
  	}
  
  	/*
  	 * Free the inode.
  	 */
9d87c3192   Eric Sandeen   [XFS] Remove the ...
1154
  	xfs_bmap_init(&free_list, &first_block);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155
1156
1157
1158
1159
1160
1161
1162
  	error = xfs_ifree(tp, ip, &free_list);
  	if (error) {
  		/*
  		 * If we fail to free the inode, shut down.  The cancel
  		 * might do that, we need to make sure.  Otherwise the
  		 * inode might be lost for a long time or forever.
  		 */
  		if (!XFS_FORCED_SHUTDOWN(mp)) {
0b932cccb   Dave Chinner   xfs: Convert rema...
1163
1164
  			xfs_notice(mp, "%s: xfs_ifree returned error %d",
  				__func__, error);
7d04a335b   Nathan Scott   [XFS] Shutdown th...
1165
  			xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1166
1167
1168
1169
1170
1171
  		}
  		xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
  	} else {
  		/*
  		 * Credit the quota account(s). The inode is gone.
  		 */
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
1172
  		xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_ICOUNT, -1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1173
1174
  
  		/*
78e9da77f   David Chinner   [XFS] Don't allow...
1175
1176
1177
  		 * Just ignore errors at this point.  There is nothing we can
  		 * do except to try to keep going. Make sure it's not a silent
  		 * error.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1178
  		 */
78e9da77f   David Chinner   [XFS] Don't allow...
1179
1180
  		error = xfs_bmap_finish(&tp,  &free_list, &committed);
  		if (error)
534877869   Dave Chinner   xfs: convert xfs_...
1181
1182
  			xfs_notice(mp, "%s: xfs_bmap_finish returned error %d",
  				__func__, error);
78e9da77f   David Chinner   [XFS] Don't allow...
1183
1184
  		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
  		if (error)
534877869   Dave Chinner   xfs: convert xfs_...
1185
1186
  			xfs_notice(mp, "%s: xfs_trans_commit returned error %d",
  				__func__, error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
  	}
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
1188

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1189
1190
1191
  	/*
  	 * Release the dquots held by inode, if any.
  	 */
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
1192
  	xfs_qm_dqdetach(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1193
1194
1195
1196
1197
  	xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
  
   out:
  	return VN_INACTIVE_CACHE;
  }
384f3ced0   Barry Naujok   [XFS] Return case...
1198
1199
1200
1201
1202
1203
  /*
   * Lookups up an inode from "name". If ci_name is not NULL, then a CI match
   * is allowed, otherwise it has to be an exact match. If a CI match is found,
   * ci_name->name will point to a the actual name (caller must free) or
   * will be set to NULL if an exact match is found.
   */
993386c19   Christoph Hellwig   [XFS] decontamina...
1204
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1205
  xfs_lookup(
993386c19   Christoph Hellwig   [XFS] decontamina...
1206
  	xfs_inode_t		*dp,
556b8b166   Barry Naujok   [XFS] remove bhv_...
1207
  	struct xfs_name		*name,
384f3ced0   Barry Naujok   [XFS] Return case...
1208
1209
  	xfs_inode_t		**ipp,
  	struct xfs_name		*ci_name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1210
  {
eca450b7c   Christoph Hellwig   [XFS] simplify xf...
1211
  	xfs_ino_t		inum;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1212
1213
  	int			error;
  	uint			lock_mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214

cca28fb83   Christoph Hellwig   xfs: split xfs_it...
1215
  	trace_xfs_lookup(dp, name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1216
1217
1218
1219
1220
  
  	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
  		return XFS_ERROR(EIO);
  
  	lock_mode = xfs_ilock_map_shared(dp);
384f3ced0   Barry Naujok   [XFS] Return case...
1221
  	error = xfs_dir_lookup(NULL, dp, name, &inum, ci_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1222
  	xfs_iunlock_map_shared(dp, lock_mode);
eca450b7c   Christoph Hellwig   [XFS] simplify xf...
1223
1224
1225
  
  	if (error)
  		goto out;
7b6259e7a   Dave Chinner   xfs: remove block...
1226
  	error = xfs_iget(dp->i_mount, NULL, inum, 0, 0, ipp);
eca450b7c   Christoph Hellwig   [XFS] simplify xf...
1227
  	if (error)
384f3ced0   Barry Naujok   [XFS] Return case...
1228
  		goto out_free_name;
eca450b7c   Christoph Hellwig   [XFS] simplify xf...
1229

eca450b7c   Christoph Hellwig   [XFS] simplify xf...
1230
  	return 0;
384f3ced0   Barry Naujok   [XFS] Return case...
1231
1232
1233
1234
  out_free_name:
  	if (ci_name)
  		kmem_free(ci_name->name);
  out:
eca450b7c   Christoph Hellwig   [XFS] simplify xf...
1235
  	*ipp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1236
1237
  	return error;
  }
993386c19   Christoph Hellwig   [XFS] decontamina...
1238
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1239
  xfs_create(
993386c19   Christoph Hellwig   [XFS] decontamina...
1240
  	xfs_inode_t		*dp,
556b8b166   Barry Naujok   [XFS] remove bhv_...
1241
  	struct xfs_name		*name,
3e5daf05a   Christoph Hellwig   [XFS] simplify xf...
1242
1243
  	mode_t			mode,
  	xfs_dev_t		rdev,
6c77b0ea1   Christoph Hellwig   xfs: remove xfs_c...
1244
  	xfs_inode_t		**ipp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1245
  {
517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1246
1247
1248
1249
  	int			is_dir = S_ISDIR(mode);
  	struct xfs_mount	*mp = dp->i_mount;
  	struct xfs_inode	*ip = NULL;
  	struct xfs_trans	*tp = NULL;
556b8b166   Barry Naujok   [XFS] remove bhv_...
1250
  	int			error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1251
1252
  	xfs_bmap_free_t		free_list;
  	xfs_fsblock_t		first_block;
993386c19   Christoph Hellwig   [XFS] decontamina...
1253
  	boolean_t		unlock_dp_on_error = B_FALSE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1254
1255
  	uint			cancel_flags;
  	int			committed;
6743099ce   Arkadiusz Mi?kiewicz   xfs: Extend proje...
1256
  	prid_t			prid;
517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1257
1258
  	struct xfs_dquot	*udqp = NULL;
  	struct xfs_dquot	*gdqp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1259
  	uint			resblks;
517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1260
1261
  	uint			log_res;
  	uint			log_count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1262

cca28fb83   Christoph Hellwig   xfs: split xfs_it...
1263
  	trace_xfs_create(dp, name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1264

517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1265
1266
  	if (XFS_FORCED_SHUTDOWN(mp))
  		return XFS_ERROR(EIO);
365ca83d5   Nathan Scott   [XFS] Add support...
1267
  	if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
6743099ce   Arkadiusz Mi?kiewicz   xfs: Extend proje...
1268
  		prid = xfs_get_projid(dp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1269
  	else
6743099ce   Arkadiusz Mi?kiewicz   xfs: Extend proje...
1270
  		prid = XFS_PROJID_DEFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1271
1272
1273
1274
  
  	/*
  	 * Make sure that we have allocated dquot(s) on disk.
  	 */
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
1275
  	error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1276
  			XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1277
  	if (error)
ec3ba85f4   Christoph Hellwig   xfs: more sensibl...
1278
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1279

517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
  	if (is_dir) {
  		rdev = 0;
  		resblks = XFS_MKDIR_SPACE_RES(mp, name->len);
  		log_res = XFS_MKDIR_LOG_RES(mp);
  		log_count = XFS_MKDIR_LOG_COUNT;
  		tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR);
  	} else {
  		resblks = XFS_CREATE_SPACE_RES(mp, name->len);
  		log_res = XFS_CREATE_LOG_RES(mp);
  		log_count = XFS_CREATE_LOG_COUNT;
  		tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1292

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1293
  	cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1294

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1295
1296
1297
1298
1299
1300
  	/*
  	 * Initially assume that the file does not exist and
  	 * reserve the resources for that case.  If that is not
  	 * the case we'll drop the one we have and get a more
  	 * appropriate transaction later.
  	 */
517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1301
1302
  	error = xfs_trans_reserve(tp, resblks, log_res, 0,
  			XFS_TRANS_PERM_LOG_RES, log_count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1303
  	if (error == ENOSPC) {
153fec43c   Dave Chinner   xfs: flush delaye...
1304
1305
  		/* flush outstanding delalloc blocks and retry */
  		xfs_flush_inodes(dp);
4734d401d   Christoph Hellwig   xfs: use correct ...
1306
1307
  		error = xfs_trans_reserve(tp, resblks, log_res, 0,
  				XFS_TRANS_PERM_LOG_RES, log_count);
153fec43c   Dave Chinner   xfs: flush delaye...
1308
1309
1310
  	}
  	if (error == ENOSPC) {
  		/* No space at all so try a "no-allocation" reservation */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1311
  		resblks = 0;
517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1312
1313
  		error = xfs_trans_reserve(tp, 0, log_res, 0,
  				XFS_TRANS_PERM_LOG_RES, log_count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1314
1315
1316
  	}
  	if (error) {
  		cancel_flags = 0;
517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1317
  		goto out_trans_cancel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318
  	}
f7c66ce3f   Lachlan McIlroy   [XFS] Add lockdep...
1319
  	xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
993386c19   Christoph Hellwig   [XFS] decontamina...
1320
  	unlock_dp_on_error = B_TRUE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1321

517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1322
1323
1324
1325
1326
1327
1328
  	/*
  	 * Check for directory link count overflow.
  	 */
  	if (is_dir && dp->i_d.di_nlink >= XFS_MAXLINK) {
  		error = XFS_ERROR(EMLINK);
  		goto out_trans_cancel;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1329

517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1330
  	xfs_bmap_init(&free_list, &first_block);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1331
1332
1333
1334
  
  	/*
  	 * Reserve disk quota and the inode.
  	 */
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
1335
  	error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, resblks, 1, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1336
  	if (error)
517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1337
  		goto out_trans_cancel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1338

556b8b166   Barry Naujok   [XFS] remove bhv_...
1339
1340
  	error = xfs_dir_canenter(tp, dp, name, resblks);
  	if (error)
517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1341
1342
1343
1344
1345
1346
1347
  		goto out_trans_cancel;
  
  	/*
  	 * A newly created regular or special file just has one directory
  	 * entry pointing to them, but a directory also the "." entry
  	 * pointing to itself.
  	 */
6c77b0ea1   Christoph Hellwig   xfs: remove xfs_c...
1348
  	error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev,
517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1349
  			       prid, resblks > 0, &ip, &committed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1350
1351
  	if (error) {
  		if (error == ENOSPC)
517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1352
1353
  			goto out_trans_cancel;
  		goto out_trans_abort;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1354
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1355
1356
  
  	/*
993386c19   Christoph Hellwig   [XFS] decontamina...
1357
1358
1359
1360
1361
  	 * Now we join the directory inode to the transaction.  We do not do it
  	 * earlier because xfs_dir_ialloc might commit the previous transaction
  	 * (and release all the locks).  An error from here on will result in
  	 * the transaction cancel unlocking dp so don't do it explicitly in the
  	 * error path.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1362
  	 */
898621d5a   Christoph Hellwig   xfs: simplify ino...
1363
  	xfs_trans_ijoin_ref(tp, dp, XFS_ILOCK_EXCL);
993386c19   Christoph Hellwig   [XFS] decontamina...
1364
  	unlock_dp_on_error = B_FALSE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1365

556b8b166   Barry Naujok   [XFS] remove bhv_...
1366
  	error = xfs_dir_createname(tp, dp, name, ip->i_ino,
f6c2d1fa6   Nathan Scott   [XFS] Remove vers...
1367
1368
  					&first_block, &free_list, resblks ?
  					resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1369
1370
  	if (error) {
  		ASSERT(error != ENOSPC);
517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1371
  		goto out_trans_abort;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1372
  	}
dcd79a142   Dave Chinner   xfs: don't use vf...
1373
  	xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1374
  	xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1375
1376
1377
1378
1379
1380
1381
1382
1383
  	if (is_dir) {
  		error = xfs_dir_init(tp, ip, dp);
  		if (error)
  			goto out_bmap_cancel;
  
  		error = xfs_bumplink(tp, dp);
  		if (error)
  			goto out_bmap_cancel;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1384
1385
1386
1387
1388
  	/*
  	 * If this is a synchronous mount, make sure that the
  	 * create transaction goes to disk before returning to
  	 * the user.
  	 */
517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1389
  	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1390
  		xfs_trans_set_sync(tp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1391

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1392
1393
1394
1395
1396
  	/*
  	 * Attach the dquot(s) to the inodes and modify them incore.
  	 * These ids of the inode couldn't have changed since the new
  	 * inode has been locked ever since it was created.
  	 */
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
1397
  	xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1398

f7c99b6fc   Eric Sandeen   [XFS] Remove unus...
1399
  	error = xfs_bmap_finish(&tp, &free_list, &committed);
517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1400
  	if (error)
ec3ba85f4   Christoph Hellwig   xfs: more sensibl...
1401
  		goto out_bmap_cancel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1402

1c72bf900   Eric Sandeen   [XFS] The last ar...
1403
  	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
ec3ba85f4   Christoph Hellwig   xfs: more sensibl...
1404
1405
  	if (error)
  		goto out_release_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1406

7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
1407
1408
  	xfs_qm_dqrele(udqp);
  	xfs_qm_dqrele(gdqp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409

979ebab11   Christoph Hellwig   [XFS] cleanup vno...
1410
  	*ipp = ip;
288699fec   Christoph Hellwig   xfs: drop dmapi h...
1411
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412

517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1413
1414
1415
   out_bmap_cancel:
  	xfs_bmap_cancel(&free_list);
   out_trans_abort:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1416
  	cancel_flags |= XFS_TRANS_ABORT;
517b5e8c8   Christoph Hellwig   xfs: merge xfs_mk...
1417
1418
   out_trans_cancel:
  	xfs_trans_cancel(tp, cancel_flags);
ec3ba85f4   Christoph Hellwig   xfs: more sensibl...
1419
1420
1421
1422
1423
1424
1425
1426
   out_release_inode:
  	/*
  	 * Wait until after the current transaction is aborted to
  	 * release the inode.  This prevents recursive transactions
  	 * and deadlocks from xfs_inactive.
  	 */
  	if (ip)
  		IRELE(ip);
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
1427
1428
  	xfs_qm_dqrele(udqp);
  	xfs_qm_dqrele(gdqp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1429

993386c19   Christoph Hellwig   [XFS] decontamina...
1430
1431
  	if (unlock_dp_on_error)
  		xfs_iunlock(dp, XFS_ILOCK_EXCL);
288699fec   Christoph Hellwig   xfs: drop dmapi h...
1432
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1433
1434
1435
  }
  
  #ifdef DEBUG
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1436
1437
1438
1439
1440
1441
1442
1443
  int xfs_locked_n;
  int xfs_small_retries;
  int xfs_middle_retries;
  int xfs_lots_retries;
  int xfs_lock_delays;
  #endif
  
  /*
f7c66ce3f   Lachlan McIlroy   [XFS] Add lockdep...
1444
1445
1446
1447
1448
1449
1450
   * Bump the subclass so xfs_lock_inodes() acquires each lock with
   * a different value
   */
  static inline int
  xfs_lock_inumorder(int lock_mode, int subclass)
  {
  	if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL))
0f1145cc1   David Chinner   [XFS] Fix lockdep...
1451
  		lock_mode |= (subclass + XFS_LOCK_INUMORDER) << XFS_IOLOCK_SHIFT;
f7c66ce3f   Lachlan McIlroy   [XFS] Add lockdep...
1452
  	if (lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL))
0f1145cc1   David Chinner   [XFS] Fix lockdep...
1453
  		lock_mode |= (subclass + XFS_LOCK_INUMORDER) << XFS_ILOCK_SHIFT;
f7c66ce3f   Lachlan McIlroy   [XFS] Add lockdep...
1454
1455
1456
1457
1458
  
  	return lock_mode;
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
   * The following routine will lock n inodes in exclusive mode.
   * We assume the caller calls us with the inodes in i_ino order.
   *
   * We need to detect deadlock where an inode that we lock
   * is in the AIL and we start waiting for another inode that is locked
   * by a thread in a long running transaction (such as truncate). This can
   * result in deadlock since the long running trans might need to wait
   * for the inode we just locked in order to push the tail and free space
   * in the log.
   */
  void
  xfs_lock_inodes(
  	xfs_inode_t	**ips,
  	int		inodes,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1473
1474
1475
1476
1477
1478
  	uint		lock_mode)
  {
  	int		attempts = 0, i, j, try_lock;
  	xfs_log_item_t	*lp;
  
  	ASSERT(ips && (inodes >= 2)); /* we need at least two */
cfa853e47   Christoph Hellwig   [XFS] remove manu...
1479
1480
  	try_lock = 0;
  	i = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
  
  again:
  	for (; i < inodes; i++) {
  		ASSERT(ips[i]);
  
  		if (i && (ips[i] == ips[i-1]))	/* Already locked */
  			continue;
  
  		/*
  		 * If try_lock is not set yet, make sure all locked inodes
  		 * are not in the AIL.
  		 * If any are, set try_lock to be used later.
  		 */
  
  		if (!try_lock) {
  			for (j = (i - 1); j >= 0 && !try_lock; j--) {
  				lp = (xfs_log_item_t *)ips[j]->i_itemp;
  				if (lp && (lp->li_flags & XFS_LI_IN_AIL)) {
  					try_lock++;
  				}
  			}
  		}
  
  		/*
  		 * If any of the previous locks we have locked is in the AIL,
  		 * we must TRY to get the second and subsequent locks. If
  		 * we can't get any, we must release all we have
  		 * and try again.
  		 */
  
  		if (try_lock) {
  			/* try_lock must be 0 if i is 0. */
  			/*
  			 * try_lock means we have an inode locked
  			 * that is in the AIL.
  			 */
  			ASSERT(i != 0);
f7c66ce3f   Lachlan McIlroy   [XFS] Add lockdep...
1518
  			if (!xfs_ilock_nowait(ips[i], xfs_lock_inumorder(lock_mode, i))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
  				attempts++;
  
  				/*
  				 * Unlock all previous guys and try again.
  				 * xfs_iunlock will try to push the tail
  				 * if the inode is in the AIL.
  				 */
  
  				for(j = i - 1; j >= 0; j--) {
  
  					/*
  					 * Check to see if we've already
  					 * unlocked this one.
  					 * Not the first one going back,
  					 * and the inode ptr is the same.
  					 */
  					if ((j != (i - 1)) && ips[j] ==
  								ips[j+1])
  						continue;
  
  					xfs_iunlock(ips[j], lock_mode);
  				}
  
  				if ((attempts % 5) == 0) {
  					delay(1); /* Don't just spin the CPU */
  #ifdef DEBUG
  					xfs_lock_delays++;
  #endif
  				}
  				i = 0;
  				try_lock = 0;
  				goto again;
  			}
  		} else {
f7c66ce3f   Lachlan McIlroy   [XFS] Add lockdep...
1553
  			xfs_ilock(ips[i], xfs_lock_inumorder(lock_mode, i));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
  		}
  	}
  
  #ifdef DEBUG
  	if (attempts) {
  		if (attempts < 5) xfs_small_retries++;
  		else if (attempts < 100) xfs_middle_retries++;
  		else xfs_lots_retries++;
  	} else {
  		xfs_locked_n++;
  	}
  #endif
  }
f9114eba1   David Chinner   [XFS] Prevent loc...
1567
1568
1569
1570
1571
1572
  /*
   * xfs_lock_two_inodes() can only be used to lock one type of lock
   * at a time - the iolock or the ilock, but not both at once. If
   * we lock both at once, lockdep will report false positives saying
   * we have violated locking orders.
   */
e1cccd917   Christoph Hellwig   [XFS] kill xfs_lo...
1573
1574
1575
1576
1577
1578
1579
1580
1581
  void
  xfs_lock_two_inodes(
  	xfs_inode_t		*ip0,
  	xfs_inode_t		*ip1,
  	uint			lock_mode)
  {
  	xfs_inode_t		*temp;
  	int			attempts = 0;
  	xfs_log_item_t		*lp;
f9114eba1   David Chinner   [XFS] Prevent loc...
1582
1583
  	if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL))
  		ASSERT((lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)) == 0);
e1cccd917   Christoph Hellwig   [XFS] kill xfs_lo...
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
  	ASSERT(ip0->i_ino != ip1->i_ino);
  
  	if (ip0->i_ino > ip1->i_ino) {
  		temp = ip0;
  		ip0 = ip1;
  		ip1 = temp;
  	}
  
   again:
  	xfs_ilock(ip0, xfs_lock_inumorder(lock_mode, 0));
  
  	/*
  	 * If the first lock we have locked is in the AIL, we must TRY to get
  	 * the second lock. If we can't get it, we must release the first one
  	 * and try again.
  	 */
  	lp = (xfs_log_item_t *)ip0->i_itemp;
  	if (lp && (lp->li_flags & XFS_LI_IN_AIL)) {
  		if (!xfs_ilock_nowait(ip1, xfs_lock_inumorder(lock_mode, 1))) {
  			xfs_iunlock(ip0, lock_mode);
  			if ((++attempts % 5) == 0)
  				delay(1); /* Don't just spin the CPU */
  			goto again;
  		}
  	} else {
  		xfs_ilock(ip1, xfs_lock_inumorder(lock_mode, 1));
  	}
  }
993386c19   Christoph Hellwig   [XFS] decontamina...
1612
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1613
  xfs_remove(
993386c19   Christoph Hellwig   [XFS] decontamina...
1614
  	xfs_inode_t             *dp,
556b8b166   Barry Naujok   [XFS] remove bhv_...
1615
1616
  	struct xfs_name		*name,
  	xfs_inode_t		*ip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1617
  {
993386c19   Christoph Hellwig   [XFS] decontamina...
1618
  	xfs_mount_t		*mp = dp->i_mount;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1619
  	xfs_trans_t             *tp = NULL;
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1620
  	int			is_dir = S_ISDIR(ip->i_d.di_mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1621
1622
1623
1624
1625
  	int                     error = 0;
  	xfs_bmap_free_t         free_list;
  	xfs_fsblock_t           first_block;
  	int			cancel_flags;
  	int			committed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1626
1627
  	int			link_zero;
  	uint			resblks;
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1628
  	uint			log_count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1629

cca28fb83   Christoph Hellwig   xfs: split xfs_it...
1630
  	trace_xfs_remove(dp, name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1631

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1632
1633
  	if (XFS_FORCED_SHUTDOWN(mp))
  		return XFS_ERROR(EIO);
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
1634
  	error = xfs_qm_dqattach(dp, 0);
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1635
1636
  	if (error)
  		goto std_return;
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
1637
  	error = xfs_qm_dqattach(ip, 0);
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1638
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1639
  		goto std_return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1640

8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1641
1642
1643
1644
1645
1646
1647
  	if (is_dir) {
  		tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR);
  		log_count = XFS_DEFAULT_LOG_COUNT;
  	} else {
  		tp = xfs_trans_alloc(mp, XFS_TRANS_REMOVE);
  		log_count = XFS_REMOVE_LOG_COUNT;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1648
  	cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1649

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
  	/*
  	 * We try to get the real space reservation first,
  	 * allowing for directory btree deletion(s) implying
  	 * possible bmap insert(s).  If we can't get the space
  	 * reservation then we use 0 instead, and avoid the bmap
  	 * btree insert(s) in the directory code by, if the bmap
  	 * insert tries to happen, instead trimming the LAST
  	 * block from the directory.
  	 */
  	resblks = XFS_REMOVE_SPACE_RES(mp);
  	error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0,
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1661
  				  XFS_TRANS_PERM_LOG_RES, log_count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1662
1663
1664
  	if (error == ENOSPC) {
  		resblks = 0;
  		error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0,
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1665
  					  XFS_TRANS_PERM_LOG_RES, log_count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1666
1667
1668
  	}
  	if (error) {
  		ASSERT(error != ENOSPC);
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1669
1670
  		cancel_flags = 0;
  		goto out_trans_cancel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1671
  	}
e1cccd917   Christoph Hellwig   [XFS] kill xfs_lo...
1672
  	xfs_lock_two_inodes(dp, ip, XFS_ILOCK_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1673

898621d5a   Christoph Hellwig   xfs: simplify ino...
1674
1675
  	xfs_trans_ijoin_ref(tp, dp, XFS_ILOCK_EXCL);
  	xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1676
1677
  
  	/*
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
  	 * If we're removing a directory perform some additional validation.
  	 */
  	if (is_dir) {
  		ASSERT(ip->i_d.di_nlink >= 2);
  		if (ip->i_d.di_nlink != 2) {
  			error = XFS_ERROR(ENOTEMPTY);
  			goto out_trans_cancel;
  		}
  		if (!xfs_dir_isempty(ip)) {
  			error = XFS_ERROR(ENOTEMPTY);
  			goto out_trans_cancel;
  		}
  	}
9d87c3192   Eric Sandeen   [XFS] Remove the ...
1691
  	xfs_bmap_init(&free_list, &first_block);
556b8b166   Barry Naujok   [XFS] remove bhv_...
1692
  	error = xfs_dir_removename(tp, dp, name, ip->i_ino,
d4377d841   Christoph Hellwig   [XFS] xfs_rename:...
1693
  					&first_block, &free_list, resblks);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1694
1695
  	if (error) {
  		ASSERT(error != ENOENT);
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1696
  		goto out_bmap_cancel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1697
  	}
dcd79a142   Dave Chinner   xfs: don't use vf...
1698
  	xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1699

8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1700
1701
1702
1703
1704
1705
1706
1707
1708
  	if (is_dir) {
  		/*
  		 * Drop the link from ip's "..".
  		 */
  		error = xfs_droplink(tp, dp);
  		if (error)
  			goto out_bmap_cancel;
  
  		/*
2b7035fd7   Christoph Hellwig   [XFS] Trivial xfs...
1709
  		 * Drop the "." link from ip to self.
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1710
1711
1712
1713
1714
1715
1716
  		 */
  		error = xfs_droplink(tp, ip);
  		if (error)
  			goto out_bmap_cancel;
  	} else {
  		/*
  		 * When removing a non-directory we need to log the parent
26c529513   Dave Chinner   [XFS] remove i_ge...
1717
1718
  		 * inode here.  For a directory this is done implicitly
  		 * by the xfs_droplink call for the ".." entry.
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1719
1720
  		 */
  		xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1721
  	}
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1722
  	/*
2b7035fd7   Christoph Hellwig   [XFS] Trivial xfs...
1723
  	 * Drop the link from dp to ip.
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1724
1725
1726
1727
1728
1729
1730
  	 */
  	error = xfs_droplink(tp, ip);
  	if (error)
  		goto out_bmap_cancel;
  
  	/*
  	 * Determine if this is the last link while
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1731
1732
  	 * we are in the transaction.
  	 */
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1733
  	link_zero = (ip->i_d.di_nlink == 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1734
1735
  
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1736
1737
1738
1739
  	 * If this is a synchronous mount, make sure that the
  	 * remove transaction goes to disk before returning to
  	 * the user.
  	 */
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1740
  	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1741
  		xfs_trans_set_sync(tp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1742

f7c99b6fc   Eric Sandeen   [XFS] Remove unus...
1743
  	error = xfs_bmap_finish(&tp, &free_list, &committed);
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1744
1745
  	if (error)
  		goto out_bmap_cancel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1746

1c72bf900   Eric Sandeen   [XFS] The last ar...
1747
  	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
5df78e73d   Christoph Hellwig   [XFS] kill usesle...
1748
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1749
  		goto std_return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1750
1751
  
  	/*
2a82b8be8   David Chinner   [XFS] Concurrent ...
1752
1753
1754
1755
1756
  	 * If we are using filestreams, kill the stream association.
  	 * If the file is still open it may get a new one but that
  	 * will get killed on last close in xfs_close() so we don't
  	 * have to worry about that.
  	 */
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1757
  	if (!is_dir && link_zero && xfs_inode_is_filestream(ip))
2a82b8be8   David Chinner   [XFS] Concurrent ...
1758
  		xfs_filestream_deassociate(ip);
288699fec   Christoph Hellwig   xfs: drop dmapi h...
1759
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1760

8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1761
   out_bmap_cancel:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1762
1763
  	xfs_bmap_cancel(&free_list);
  	cancel_flags |= XFS_TRANS_ABORT;
8f112e3bc   Christoph Hellwig   [XFS] Merge xfs_r...
1764
   out_trans_cancel:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1765
  	xfs_trans_cancel(tp, cancel_flags);
288699fec   Christoph Hellwig   xfs: drop dmapi h...
1766
1767
   std_return:
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1768
  }
993386c19   Christoph Hellwig   [XFS] decontamina...
1769
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1770
  xfs_link(
993386c19   Christoph Hellwig   [XFS] decontamina...
1771
  	xfs_inode_t		*tdp,
a3da78964   Christoph Hellwig   [XFS] cleanup vno...
1772
  	xfs_inode_t		*sip,
556b8b166   Barry Naujok   [XFS] remove bhv_...
1773
  	struct xfs_name		*target_name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1774
  {
993386c19   Christoph Hellwig   [XFS] decontamina...
1775
  	xfs_mount_t		*mp = tdp->i_mount;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1776
  	xfs_trans_t		*tp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1777
1778
1779
1780
1781
  	int			error;
  	xfs_bmap_free_t         free_list;
  	xfs_fsblock_t           first_block;
  	int			cancel_flags;
  	int			committed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1782
  	int			resblks;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1783

cca28fb83   Christoph Hellwig   xfs: split xfs_it...
1784
  	trace_xfs_link(tdp, target_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1785

a3da78964   Christoph Hellwig   [XFS] cleanup vno...
1786
  	ASSERT(!S_ISDIR(sip->i_d.di_mode));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1787

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1788
1789
  	if (XFS_FORCED_SHUTDOWN(mp))
  		return XFS_ERROR(EIO);
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
1790
  	error = xfs_qm_dqattach(sip, 0);
cb3f35bb3   Christoph Hellwig   xfs: tiny cleanup...
1791
1792
  	if (error)
  		goto std_return;
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
1793
  	error = xfs_qm_dqattach(tdp, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1794
1795
1796
1797
1798
  	if (error)
  		goto std_return;
  
  	tp = xfs_trans_alloc(mp, XFS_TRANS_LINK);
  	cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
556b8b166   Barry Naujok   [XFS] remove bhv_...
1799
  	resblks = XFS_LINK_SPACE_RES(mp, target_name->len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
  	error = xfs_trans_reserve(tp, resblks, XFS_LINK_LOG_RES(mp), 0,
  			XFS_TRANS_PERM_LOG_RES, XFS_LINK_LOG_COUNT);
  	if (error == ENOSPC) {
  		resblks = 0;
  		error = xfs_trans_reserve(tp, 0, XFS_LINK_LOG_RES(mp), 0,
  				XFS_TRANS_PERM_LOG_RES, XFS_LINK_LOG_COUNT);
  	}
  	if (error) {
  		cancel_flags = 0;
  		goto error_return;
  	}
e1cccd917   Christoph Hellwig   [XFS] kill xfs_lo...
1811
  	xfs_lock_two_inodes(sip, tdp, XFS_ILOCK_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1812

898621d5a   Christoph Hellwig   xfs: simplify ino...
1813
1814
  	xfs_trans_ijoin_ref(tp, sip, XFS_ILOCK_EXCL);
  	xfs_trans_ijoin_ref(tp, tdp, XFS_ILOCK_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1815
1816
1817
1818
1819
1820
1821
1822
  
  	/*
  	 * If the source has too many links, we can't make any more to it.
  	 */
  	if (sip->i_d.di_nlink >= XFS_MAXLINK) {
  		error = XFS_ERROR(EMLINK);
  		goto error_return;
  	}
365ca83d5   Nathan Scott   [XFS] Add support...
1823
1824
1825
1826
1827
1828
  	/*
  	 * If we are using project inheritance, we only allow hard link
  	 * creation in our tree when the project IDs are the same; else
  	 * the tree quota mechanism could be circumvented.
  	 */
  	if (unlikely((tdp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
6743099ce   Arkadiusz Mi?kiewicz   xfs: Extend proje...
1829
  		     (xfs_get_projid(tdp) != xfs_get_projid(sip)))) {
b1ecdda93   Nathan Scott   [XFS] Fix a proje...
1830
  		error = XFS_ERROR(EXDEV);
365ca83d5   Nathan Scott   [XFS] Add support...
1831
1832
  		goto error_return;
  	}
556b8b166   Barry Naujok   [XFS] remove bhv_...
1833
1834
  	error = xfs_dir_canenter(tp, tdp, target_name, resblks);
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1835
  		goto error_return;
9d87c3192   Eric Sandeen   [XFS] Remove the ...
1836
  	xfs_bmap_init(&free_list, &first_block);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1837

556b8b166   Barry Naujok   [XFS] remove bhv_...
1838
1839
  	error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
  					&first_block, &free_list, resblks);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1840
1841
  	if (error)
  		goto abort_return;
dcd79a142   Dave Chinner   xfs: don't use vf...
1842
  	xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1843
1844
1845
  	xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);
  
  	error = xfs_bumplink(tp, sip);
b71d300c8   Alexey Dobriyan   [XFS] link(2) on ...
1846
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1847
  		goto abort_return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1848
1849
1850
1851
1852
1853
1854
1855
1856
  
  	/*
  	 * If this is a synchronous mount, make sure that the
  	 * link transaction goes to disk before returning to
  	 * the user.
  	 */
  	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
  		xfs_trans_set_sync(tp);
  	}
f7c99b6fc   Eric Sandeen   [XFS] Remove unus...
1857
  	error = xfs_bmap_finish (&tp, &free_list, &committed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1858
1859
1860
1861
  	if (error) {
  		xfs_bmap_cancel(&free_list);
  		goto abort_return;
  	}
288699fec   Christoph Hellwig   xfs: drop dmapi h...
1862
  	return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1863
1864
1865
  
   abort_return:
  	cancel_flags |= XFS_TRANS_ABORT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1866
1867
   error_return:
  	xfs_trans_cancel(tp, cancel_flags);
288699fec   Christoph Hellwig   xfs: drop dmapi h...
1868
1869
   std_return:
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1870
  }
b71d300c8   Alexey Dobriyan   [XFS] link(2) on ...
1871

993386c19   Christoph Hellwig   [XFS] decontamina...
1872
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1873
  xfs_symlink(
993386c19   Christoph Hellwig   [XFS] decontamina...
1874
  	xfs_inode_t		*dp,
556b8b166   Barry Naujok   [XFS] remove bhv_...
1875
1876
  	struct xfs_name		*link_name,
  	const char		*target_path,
3e5daf05a   Christoph Hellwig   [XFS] simplify xf...
1877
  	mode_t			mode,
6c77b0ea1   Christoph Hellwig   xfs: remove xfs_c...
1878
  	xfs_inode_t		**ipp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1879
  {
993386c19   Christoph Hellwig   [XFS] decontamina...
1880
  	xfs_mount_t		*mp = dp->i_mount;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1881
  	xfs_trans_t		*tp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1882
1883
1884
1885
1886
  	xfs_inode_t		*ip;
  	int			error;
  	int			pathlen;
  	xfs_bmap_free_t		free_list;
  	xfs_fsblock_t		first_block;
993386c19   Christoph Hellwig   [XFS] decontamina...
1887
  	boolean_t		unlock_dp_on_error = B_FALSE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1888
1889
1890
1891
1892
1893
1894
  	uint			cancel_flags;
  	int			committed;
  	xfs_fileoff_t		first_fsb;
  	xfs_filblks_t		fs_blocks;
  	int			nmaps;
  	xfs_bmbt_irec_t		mval[SYMLINK_MAPS];
  	xfs_daddr_t		d;
556b8b166   Barry Naujok   [XFS] remove bhv_...
1895
  	const char		*cur_chunk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1896
1897
1898
  	int			byte_cnt;
  	int			n;
  	xfs_buf_t		*bp;
6743099ce   Arkadiusz Mi?kiewicz   xfs: Extend proje...
1899
  	prid_t			prid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1900
1901
  	struct xfs_dquot	*udqp, *gdqp;
  	uint			resblks;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1902

3937be5ba   Christoph Hellwig   [XFS] cleanup vno...
1903
  	*ipp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1904
1905
1906
  	error = 0;
  	ip = NULL;
  	tp = NULL;
cca28fb83   Christoph Hellwig   xfs: split xfs_it...
1907
  	trace_xfs_symlink(dp, link_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1908
1909
1910
  
  	if (XFS_FORCED_SHUTDOWN(mp))
  		return XFS_ERROR(EIO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1911
1912
1913
1914
1915
1916
  	/*
  	 * Check component lengths of the target path name.
  	 */
  	pathlen = strlen(target_path);
  	if (pathlen >= MAXPATHLEN)      /* total string too long */
  		return XFS_ERROR(ENAMETOOLONG);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1917

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1918
  	udqp = gdqp = NULL;
365ca83d5   Nathan Scott   [XFS] Add support...
1919
  	if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
6743099ce   Arkadiusz Mi?kiewicz   xfs: Extend proje...
1920
  		prid = xfs_get_projid(dp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1921
  	else
6743099ce   Arkadiusz Mi?kiewicz   xfs: Extend proje...
1922
  		prid = XFS_PROJID_DEFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1923
1924
1925
1926
  
  	/*
  	 * Make sure that we have allocated dquot(s) on disk.
  	 */
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
1927
  	error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
  			XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
  	if (error)
  		goto std_return;
  
  	tp = xfs_trans_alloc(mp, XFS_TRANS_SYMLINK);
  	cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
  	/*
  	 * The symlink will fit into the inode data fork?
  	 * There can't be any attributes so we get the whole variable part.
  	 */
  	if (pathlen <= XFS_LITINO(mp))
  		fs_blocks = 0;
  	else
  		fs_blocks = XFS_B_TO_FSB(mp, pathlen);
556b8b166   Barry Naujok   [XFS] remove bhv_...
1942
  	resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1943
1944
1945
1946
1947
1948
1949
1950
1951
  	error = xfs_trans_reserve(tp, resblks, XFS_SYMLINK_LOG_RES(mp), 0,
  			XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT);
  	if (error == ENOSPC && fs_blocks == 0) {
  		resblks = 0;
  		error = xfs_trans_reserve(tp, 0, XFS_SYMLINK_LOG_RES(mp), 0,
  				XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT);
  	}
  	if (error) {
  		cancel_flags = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1952
1953
  		goto error_return;
  	}
f7c66ce3f   Lachlan McIlroy   [XFS] Add lockdep...
1954
  	xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
993386c19   Christoph Hellwig   [XFS] decontamina...
1955
  	unlock_dp_on_error = B_TRUE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
  
  	/*
  	 * Check whether the directory allows new symlinks or not.
  	 */
  	if (dp->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) {
  		error = XFS_ERROR(EPERM);
  		goto error_return;
  	}
  
  	/*
  	 * Reserve disk quota : blocks and inode.
  	 */
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
1968
  	error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, resblks, 1, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1969
1970
1971
1972
1973
1974
  	if (error)
  		goto error_return;
  
  	/*
  	 * Check for ability to enter directory entry, if no space reserved.
  	 */
556b8b166   Barry Naujok   [XFS] remove bhv_...
1975
1976
  	error = xfs_dir_canenter(tp, dp, link_name, resblks);
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1977
1978
1979
1980
1981
  		goto error_return;
  	/*
  	 * Initialize the bmap freelist prior to calling either
  	 * bmapi or the directory create code.
  	 */
9d87c3192   Eric Sandeen   [XFS] Remove the ...
1982
  	xfs_bmap_init(&free_list, &first_block);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1983
1984
1985
1986
  
  	/*
  	 * Allocate an inode for the symlink.
  	 */
6c77b0ea1   Christoph Hellwig   xfs: remove xfs_c...
1987
1988
  	error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (mode & ~S_IFMT), 1, 0,
  			       prid, resblks > 0, &ip, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1989
1990
1991
1992
1993
  	if (error) {
  		if (error == ENOSPC)
  			goto error_return;
  		goto error1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1994

993386c19   Christoph Hellwig   [XFS] decontamina...
1995
1996
1997
1998
1999
  	/*
  	 * An error after we've joined dp to the transaction will result in the
  	 * transaction cancel unlocking dp so don't do it explicitly in the
  	 * error path.
  	 */
898621d5a   Christoph Hellwig   xfs: simplify ino...
2000
  	xfs_trans_ijoin_ref(tp, dp, XFS_ILOCK_EXCL);
993386c19   Christoph Hellwig   [XFS] decontamina...
2001
  	unlock_dp_on_error = B_FALSE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2002
2003
2004
2005
  
  	/*
  	 * Also attach the dquot(s) to it, if applicable.
  	 */
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2006
  	xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
  
  	if (resblks)
  		resblks -= XFS_IALLOC_SPACE_RES(mp);
  	/*
  	 * If the symlink will fit into the inode, write it inline.
  	 */
  	if (pathlen <= XFS_IFORK_DSIZE(ip)) {
  		xfs_idata_realloc(ip, pathlen, XFS_DATA_FORK);
  		memcpy(ip->i_df.if_u1.if_data, target_path, pathlen);
  		ip->i_d.di_size = pathlen;
  
  		/*
  		 * The inode was initially created in extent format.
  		 */
  		ip->i_df.if_flags &= ~(XFS_IFEXTENTS | XFS_IFBROOT);
  		ip->i_df.if_flags |= XFS_IFINLINE;
  
  		ip->i_d.di_format = XFS_DINODE_FMT_LOCAL;
  		xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE);
  
  	} else {
  		first_fsb = 0;
  		nmaps = SYMLINK_MAPS;
  
  		error = xfs_bmapi(tp, ip, first_fsb, fs_blocks,
  				  XFS_BMAPI_WRITE | XFS_BMAPI_METADATA,
  				  &first_block, resblks, mval, &nmaps,
b4e9181e7   Christoph Hellwig   xfs: remove unuse...
2034
  				  &free_list);
ec3ba85f4   Christoph Hellwig   xfs: more sensibl...
2035
2036
  		if (error)
  			goto error2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
  
  		if (resblks)
  			resblks -= fs_blocks;
  		ip->i_d.di_size = pathlen;
  		xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
  
  		cur_chunk = target_path;
  		for (n = 0; n < nmaps; n++) {
  			d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
  			byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
  			bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
  					       BTOBB(byte_cnt), 0);
  			ASSERT(bp && !XFS_BUF_GETERROR(bp));
  			if (pathlen < byte_cnt) {
  				byte_cnt = pathlen;
  			}
  			pathlen -= byte_cnt;
  
  			memcpy(XFS_BUF_PTR(bp), cur_chunk, byte_cnt);
  			cur_chunk += byte_cnt;
  
  			xfs_trans_log_buf(tp, bp, 0, byte_cnt - 1);
  		}
  	}
  
  	/*
  	 * Create the directory entry for the symlink.
  	 */
556b8b166   Barry Naujok   [XFS] remove bhv_...
2065
2066
  	error = xfs_dir_createname(tp, dp, link_name, ip->i_ino,
  					&first_block, &free_list, resblks);
f6c2d1fa6   Nathan Scott   [XFS] Remove vers...
2067
  	if (error)
ec3ba85f4   Christoph Hellwig   xfs: more sensibl...
2068
  		goto error2;
dcd79a142   Dave Chinner   xfs: don't use vf...
2069
  	xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2070
2071
2072
  	xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
  
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2073
2074
2075
2076
2077
2078
2079
  	 * If this is a synchronous mount, make sure that the
  	 * symlink transaction goes to disk before returning to
  	 * the user.
  	 */
  	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
  		xfs_trans_set_sync(tp);
  	}
f7c99b6fc   Eric Sandeen   [XFS] Remove unus...
2080
  	error = xfs_bmap_finish(&tp, &free_list, &committed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2081
2082
2083
  	if (error) {
  		goto error2;
  	}
1c72bf900   Eric Sandeen   [XFS] The last ar...
2084
  	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2085
2086
  	xfs_qm_dqrele(udqp);
  	xfs_qm_dqrele(gdqp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2087

288699fec   Christoph Hellwig   xfs: drop dmapi h...
2088
2089
  	*ipp = ip;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2090
2091
2092
2093
2094
2095
2096
2097
  
   error2:
  	IRELE(ip);
   error1:
  	xfs_bmap_cancel(&free_list);
  	cancel_flags |= XFS_TRANS_ABORT;
   error_return:
  	xfs_trans_cancel(tp, cancel_flags);
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2098
2099
  	xfs_qm_dqrele(udqp);
  	xfs_qm_dqrele(gdqp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2100

993386c19   Christoph Hellwig   [XFS] decontamina...
2101
  	if (unlock_dp_on_error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2102
  		xfs_iunlock(dp, XFS_ILOCK_EXCL);
288699fec   Christoph Hellwig   xfs: drop dmapi h...
2103
2104
   std_return:
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2105
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2106
  int
993386c19   Christoph Hellwig   [XFS] decontamina...
2107
2108
  xfs_set_dmattrs(
  	xfs_inode_t     *ip,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2109
  	u_int		evmask,
993386c19   Christoph Hellwig   [XFS] decontamina...
2110
  	u_int16_t	state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2111
  {
993386c19   Christoph Hellwig   [XFS] decontamina...
2112
  	xfs_mount_t	*mp = ip->i_mount;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2113
  	xfs_trans_t	*tp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2114
2115
2116
2117
  	int		error;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return XFS_ERROR(EPERM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
  	if (XFS_FORCED_SHUTDOWN(mp))
  		return XFS_ERROR(EIO);
  
  	tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS);
  	error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES (mp), 0, 0, 0);
  	if (error) {
  		xfs_trans_cancel(tp, 0);
  		return error;
  	}
  	xfs_ilock(ip, XFS_ILOCK_EXCL);
898621d5a   Christoph Hellwig   xfs: simplify ino...
2128
  	xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2129

613d70436   Christoph Hellwig   [XFS] kill xfs_io...
2130
2131
  	ip->i_d.di_dmevmask = evmask;
  	ip->i_d.di_dmstate  = state;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2132
2133
  
  	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
1c72bf900   Eric Sandeen   [XFS] The last ar...
2134
  	error = xfs_trans_commit(tp, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2135
2136
2137
  
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
  /*
   * xfs_alloc_file_space()
   *      This routine allocates disk space for the given file.
   *
   *	If alloc_type == 0, this request is for an ALLOCSP type
   *	request which will change the file size.  In this case, no
   *	DMAPI event will be generated by the call.  A TRUNCATE event
   *	will be generated later by xfs_setattr.
   *
   *	If alloc_type != 0, this request is for a RESVSP type
   *	request, and a DMAPI DM_EVENT_WRITE will be generated if the
   *	lower block boundary byte address is less than the file's
   *	length.
   *
   * RETURNS:
   *       0 on success
   *      errno on error
   *
   */
ba0f32d46   Christoph Hellwig   [XFS] mark variou...
2157
  STATIC int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2158
2159
2160
2161
2162
2163
2164
  xfs_alloc_file_space(
  	xfs_inode_t		*ip,
  	xfs_off_t		offset,
  	xfs_off_t		len,
  	int			alloc_type,
  	int			attr_flags)
  {
dd9f438e3   Nathan Scott   [XFS] Implement t...
2165
2166
  	xfs_mount_t		*mp = ip->i_mount;
  	xfs_off_t		count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2167
2168
  	xfs_filblks_t		allocated_fsb;
  	xfs_filblks_t		allocatesize_fsb;
dd9f438e3   Nathan Scott   [XFS] Implement t...
2169
2170
  	xfs_extlen_t		extsz, temp;
  	xfs_fileoff_t		startoffset_fsb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2171
  	xfs_fsblock_t		firstfsb;
dd9f438e3   Nathan Scott   [XFS] Implement t...
2172
2173
2174
  	int			nimaps;
  	int			bmapi_flag;
  	int			quota_flag;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2175
  	int			rt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2176
  	xfs_trans_t		*tp;
dd9f438e3   Nathan Scott   [XFS] Implement t...
2177
2178
2179
2180
2181
  	xfs_bmbt_irec_t		imaps[1], *imapp;
  	xfs_bmap_free_t		free_list;
  	uint			qblocks, resblks, resrtextents;
  	int			committed;
  	int			error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2182

cca28fb83   Christoph Hellwig   xfs: split xfs_it...
2183
  	trace_xfs_alloc_file_space(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2184
2185
2186
  
  	if (XFS_FORCED_SHUTDOWN(mp))
  		return XFS_ERROR(EIO);
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2187
2188
  	error = xfs_qm_dqattach(ip, 0);
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2189
2190
2191
2192
  		return error;
  
  	if (len <= 0)
  		return XFS_ERROR(EINVAL);
957d0ebed   David Chinner   [XFS] Cleanup ino...
2193
2194
  	rt = XFS_IS_REALTIME_INODE(ip);
  	extsz = xfs_get_extsz_hint(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2195
  	count = len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2196
  	imapp = &imaps[0];
dd9f438e3   Nathan Scott   [XFS] Implement t...
2197
  	nimaps = 1;
447223520   Dave Chinner   xfs: Introduce XF...
2198
  	bmapi_flag = XFS_BMAPI_WRITE | alloc_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2199
2200
  	startoffset_fsb	= XFS_B_TO_FSBT(mp, offset);
  	allocatesize_fsb = XFS_B_TO_FSB(mp, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2201
  	/*
dd9f438e3   Nathan Scott   [XFS] Implement t...
2202
  	 * Allocate file space until done or until there is an error
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2203
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2204
  	while (allocatesize_fsb && !error) {
dd9f438e3   Nathan Scott   [XFS] Implement t...
2205
  		xfs_fileoff_t	s, e;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2206
  		/*
3ddb8fa98   Nathan Scott   [XFS] Sort out co...
2207
  		 * Determine space reservations for data/realtime.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2208
  		 */
dd9f438e3   Nathan Scott   [XFS] Implement t...
2209
  		if (unlikely(extsz)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2210
  			s = startoffset_fsb;
dd9f438e3   Nathan Scott   [XFS] Implement t...
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
  			do_div(s, extsz);
  			s *= extsz;
  			e = startoffset_fsb + allocatesize_fsb;
  			if ((temp = do_mod(startoffset_fsb, extsz)))
  				e += temp;
  			if ((temp = do_mod(e, extsz)))
  				e += extsz - temp;
  		} else {
  			s = 0;
  			e = allocatesize_fsb;
  		}
72656c46f   Dave Chinner   xfs: prevent 32bi...
2222
2223
2224
2225
2226
2227
2228
2229
  		/*
  		 * The transaction reservation is limited to a 32-bit block
  		 * count, hence we need to limit the number of blocks we are
  		 * trying to reserve to avoid an overflow. We can't allocate
  		 * more than @nimaps extents, and an extent is limited on disk
  		 * to MAXEXTLEN (21 bits), so use that to enforce the limit.
  		 */
  		resblks = min_t(xfs_fileoff_t, (e - s), (MAXEXTLEN * nimaps));
dd9f438e3   Nathan Scott   [XFS] Implement t...
2230
  		if (unlikely(rt)) {
72656c46f   Dave Chinner   xfs: prevent 32bi...
2231
  			resrtextents = qblocks = resblks;
dd9f438e3   Nathan Scott   [XFS] Implement t...
2232
2233
2234
  			resrtextents /= mp->m_sb.sb_rextsize;
  			resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
  			quota_flag = XFS_QMOPT_RES_RTBLKS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2235
  		} else {
dd9f438e3   Nathan Scott   [XFS] Implement t...
2236
  			resrtextents = 0;
72656c46f   Dave Chinner   xfs: prevent 32bi...
2237
  			resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, resblks);
dd9f438e3   Nathan Scott   [XFS] Implement t...
2238
  			quota_flag = XFS_QMOPT_RES_REGBLKS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2239
2240
2241
  		}
  
  		/*
dd9f438e3   Nathan Scott   [XFS] Implement t...
2242
  		 * Allocate and setup the transaction.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2243
2244
  		 */
  		tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
dd9f438e3   Nathan Scott   [XFS] Implement t...
2245
2246
  		error = xfs_trans_reserve(tp, resblks,
  					  XFS_WRITE_LOG_RES(mp), resrtextents,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2247
2248
  					  XFS_TRANS_PERM_LOG_RES,
  					  XFS_WRITE_LOG_COUNT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2249
  		/*
dd9f438e3   Nathan Scott   [XFS] Implement t...
2250
  		 * Check for running out of space
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
  		 */
  		if (error) {
  			/*
  			 * Free the transaction structure.
  			 */
  			ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp));
  			xfs_trans_cancel(tp, 0);
  			break;
  		}
  		xfs_ilock(ip, XFS_ILOCK_EXCL);
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2261
2262
  		error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks,
  						      0, quota_flag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2263
2264
  		if (error)
  			goto error1;
898621d5a   Christoph Hellwig   xfs: simplify ino...
2265
  		xfs_trans_ijoin(tp, ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2266
2267
  
  		/*
dd9f438e3   Nathan Scott   [XFS] Implement t...
2268
  		 * Issue the xfs_bmapi() call to allocate the blocks
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2269
  		 */
9d87c3192   Eric Sandeen   [XFS] Remove the ...
2270
  		xfs_bmap_init(&free_list, &firstfsb);
541d7d3c4   Lachlan McIlroy   [XFS] kill unness...
2271
  		error = xfs_bmapi(tp, ip, startoffset_fsb,
dd9f438e3   Nathan Scott   [XFS] Implement t...
2272
2273
  				  allocatesize_fsb, bmapi_flag,
  				  &firstfsb, 0, imapp, &nimaps,
b4e9181e7   Christoph Hellwig   xfs: remove unuse...
2274
  				  &free_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2275
2276
2277
2278
2279
  		if (error) {
  			goto error0;
  		}
  
  		/*
dd9f438e3   Nathan Scott   [XFS] Implement t...
2280
  		 * Complete the transaction
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2281
  		 */
f7c99b6fc   Eric Sandeen   [XFS] Remove unus...
2282
  		error = xfs_bmap_finish(&tp, &free_list, &committed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2283
2284
2285
  		if (error) {
  			goto error0;
  		}
1c72bf900   Eric Sandeen   [XFS] The last ar...
2286
  		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2287
2288
2289
2290
2291
2292
  		xfs_iunlock(ip, XFS_ILOCK_EXCL);
  		if (error) {
  			break;
  		}
  
  		allocated_fsb = imapp->br_blockcount;
dd9f438e3   Nathan Scott   [XFS] Implement t...
2293
  		if (nimaps == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2294
2295
2296
2297
2298
2299
2300
  			error = XFS_ERROR(ENOSPC);
  			break;
  		}
  
  		startoffset_fsb += allocated_fsb;
  		allocatesize_fsb -= allocated_fsb;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2301
2302
  
  	return error;
dd9f438e3   Nathan Scott   [XFS] Implement t...
2303
  error0:	/* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2304
  	xfs_bmap_cancel(&free_list);
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2305
  	xfs_trans_unreserve_quota_nblks(tp, ip, qblocks, 0, quota_flag);
dd9f438e3   Nathan Scott   [XFS] Implement t...
2306
2307
  
  error1:	/* Just cancel transaction */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2308
2309
  	xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
  	xfs_iunlock(ip, XFS_ILOCK_EXCL);
288699fec   Christoph Hellwig   xfs: drop dmapi h...
2310
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2311
2312
2313
2314
2315
  }
  
  /*
   * Zero file bytes between startoff and endoff inclusive.
   * The iolock is held exclusive and no blocks are buffered.
2fd6f6ec6   Lachlan McIlroy   [XFS] Don't do I/...
2316
2317
2318
2319
2320
2321
2322
   *
   * This function is used by xfs_free_file_space() to zero
   * partial blocks when the range to free is not block aligned.
   * When unreserving space with boundaries that are not block
   * aligned we round up the start and round down the end
   * boundaries and then use this function to zero the parts of
   * the blocks that got dropped during the rounding.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
   */
  STATIC int
  xfs_zero_remaining_bytes(
  	xfs_inode_t		*ip,
  	xfs_off_t		startoff,
  	xfs_off_t		endoff)
  {
  	xfs_bmbt_irec_t		imap;
  	xfs_fileoff_t		offset_fsb;
  	xfs_off_t		lastoffset;
  	xfs_off_t		offset;
  	xfs_buf_t		*bp;
  	xfs_mount_t		*mp = ip->i_mount;
  	int			nimap;
  	int			error = 0;
2fd6f6ec6   Lachlan McIlroy   [XFS] Don't do I/...
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
  	/*
  	 * Avoid doing I/O beyond eof - it's not necessary
  	 * since nothing can read beyond eof.  The space will
  	 * be zeroed when the file is extended anyway.
  	 */
  	if (startoff >= ip->i_size)
  		return 0;
  
  	if (endoff > ip->i_size)
  		endoff = ip->i_size;
686865f76   Dave Chinner   xfs: rename xfs_b...
2348
2349
2350
  	bp = xfs_buf_get_uncached(XFS_IS_REALTIME_INODE(ip) ?
  					mp->m_rtdev_targp : mp->m_ddev_targp,
  				mp->m_sb.sb_blocksize, XBF_DONT_BLOCK);
c6422617a   Lachlan McIlroy   [XFS] Check retur...
2351
2352
  	if (!bp)
  		return XFS_ERROR(ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2353
2354
2355
2356
  
  	for (offset = startoff; offset <= endoff; offset = lastoffset + 1) {
  		offset_fsb = XFS_B_TO_FSBT(mp, offset);
  		nimap = 1;
541d7d3c4   Lachlan McIlroy   [XFS] kill unness...
2357
  		error = xfs_bmapi(NULL, ip, offset_fsb, 1, 0,
b4e9181e7   Christoph Hellwig   xfs: remove unuse...
2358
  			NULL, 0, &imap, &nimap, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
  		if (error || nimap < 1)
  			break;
  		ASSERT(imap.br_blockcount >= 1);
  		ASSERT(imap.br_startoff == offset_fsb);
  		lastoffset = XFS_FSB_TO_B(mp, imap.br_startoff + 1) - 1;
  		if (lastoffset > endoff)
  			lastoffset = endoff;
  		if (imap.br_startblock == HOLESTARTBLOCK)
  			continue;
  		ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
  		if (imap.br_state == XFS_EXT_UNWRITTEN)
  			continue;
  		XFS_BUF_UNDONE(bp);
  		XFS_BUF_UNWRITE(bp);
  		XFS_BUF_READ(bp);
9d87c3192   Eric Sandeen   [XFS] Remove the ...
2374
  		XFS_BUF_SET_ADDR(bp, xfs_fsb_to_db(ip, imap.br_startblock));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2375
  		xfsbdstrat(mp, bp);
1a1a3e97b   Christoph Hellwig   xfs: remove xfs_b...
2376
  		error = xfs_buf_iowait(bp);
d64e31a2f   David Chinner   [XFS] Ensure erro...
2377
  		if (error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
  			xfs_ioerror_alert("xfs_zero_remaining_bytes(read)",
  					  mp, bp, XFS_BUF_ADDR(bp));
  			break;
  		}
  		memset(XFS_BUF_PTR(bp) +
  			(offset - XFS_FSB_TO_B(mp, imap.br_startoff)),
  		      0, lastoffset - offset + 1);
  		XFS_BUF_UNDONE(bp);
  		XFS_BUF_UNREAD(bp);
  		XFS_BUF_WRITE(bp);
  		xfsbdstrat(mp, bp);
1a1a3e97b   Christoph Hellwig   xfs: remove xfs_b...
2389
  		error = xfs_buf_iowait(bp);
d64e31a2f   David Chinner   [XFS] Ensure erro...
2390
  		if (error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
  			xfs_ioerror_alert("xfs_zero_remaining_bytes(write)",
  					  mp, bp, XFS_BUF_ADDR(bp));
  			break;
  		}
  	}
  	xfs_buf_free(bp);
  	return error;
  }
  
  /*
   * xfs_free_file_space()
   *      This routine frees disk space for the given file.
   *
   *	This routine is only called by xfs_change_file_space
   *	for an UNRESVSP type call.
   *
   * RETURNS:
   *       0 on success
   *      errno on error
   *
   */
  STATIC int
  xfs_free_file_space(
  	xfs_inode_t		*ip,
  	xfs_off_t		offset,
  	xfs_off_t		len,
  	int			attr_flags)
  {
  	int			committed;
  	int			done;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2421
2422
2423
2424
  	xfs_fileoff_t		endoffset_fsb;
  	int			error;
  	xfs_fsblock_t		firstfsb;
  	xfs_bmap_free_t		free_list;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2425
2426
2427
2428
2429
2430
  	xfs_bmbt_irec_t		imap;
  	xfs_off_t		ioffset;
  	xfs_extlen_t		mod=0;
  	xfs_mount_t		*mp;
  	int			nimap;
  	uint			resblks;
673cdf5c7   Nathan Scott   [XFS] Fix roundin...
2431
  	uint			rounding;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2432
2433
2434
  	int			rt;
  	xfs_fileoff_t		startoffset_fsb;
  	xfs_trans_t		*tp;
5fcbab355   Dean Roehrich   [XFS] Add ATTR_NO...
2435
  	int			need_iolock = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2436

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2437
  	mp = ip->i_mount;
cca28fb83   Christoph Hellwig   xfs: split xfs_it...
2438
  	trace_xfs_free_file_space(ip);
bd5a876ac   Christoph Hellwig   [XFS] (mostly) re...
2439

7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2440
2441
  	error = xfs_qm_dqattach(ip, 0);
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2442
2443
2444
2445
2446
  		return error;
  
  	error = 0;
  	if (len <= 0)	/* if nothing being freed */
  		return error;
71ddabb94   Eric Sandeen   [XFS] optimize XF...
2447
  	rt = XFS_IS_REALTIME_INODE(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2448
  	startoffset_fsb	= XFS_B_TO_FSB(mp, offset);
288699fec   Christoph Hellwig   xfs: drop dmapi h...
2449
  	endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2450

0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
2451
  	if (attr_flags & XFS_ATTR_NOLOCK)
5fcbab355   Dean Roehrich   [XFS] Add ATTR_NO...
2452
  		need_iolock = 0;
9fa8046f5   Yingping Lu   [XFS] Fixing the ...
2453
  	if (need_iolock) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2454
  		xfs_ilock(ip, XFS_IOLOCK_EXCL);
25e41b3d5   Christoph Hellwig   move vn_iowait / ...
2455
2456
  		/* wait for the completion of any pending DIOs */
  		xfs_ioend_wait(ip);
9fa8046f5   Yingping Lu   [XFS] Fixing the ...
2457
  	}
5fcbab355   Dean Roehrich   [XFS] Add ATTR_NO...
2458

e6a4b37f3   Tim Shimmin   [XFS] Remove the ...
2459
  	rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2460
  	ioffset = offset & ~(rounding - 1);
bd5a876ac   Christoph Hellwig   [XFS] (mostly) re...
2461

df80c933f   Christoph Hellwig   [XFS] remove some...
2462
  	if (VN_CACHED(VFS_I(ip)) != 0) {
e6a4b37f3   Tim Shimmin   [XFS] Remove the ...
2463
  		error = xfs_flushinval_pages(ip, ioffset, -1, FI_REMAPF_LOCKED);
d3cf20947   Lachlan McIlroy   [XFS] propogate r...
2464
2465
  		if (error)
  			goto out_unlock_iolock;
bd5a876ac   Christoph Hellwig   [XFS] (mostly) re...
2466
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2467
2468
  	/*
  	 * Need to zero the stuff we're not freeing, on disk.
9da096fd1   Malcolm Parsons   xfs: fix various ...
2469
  	 * If it's a realtime file & can't use unwritten extents then we
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2470
2471
2472
  	 * actually need to zero the extent edges.  Otherwise xfs_bunmapi
  	 * will take care of it for us.
  	 */
621187099   Eric Sandeen   [XFS] remove shou...
2473
  	if (rt && !xfs_sb_version_hasextflgbit(&mp->m_sb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2474
  		nimap = 1;
541d7d3c4   Lachlan McIlroy   [XFS] kill unness...
2475
  		error = xfs_bmapi(NULL, ip, startoffset_fsb,
b4e9181e7   Christoph Hellwig   xfs: remove unuse...
2476
  			1, 0, NULL, 0, &imap, &nimap, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
  		if (error)
  			goto out_unlock_iolock;
  		ASSERT(nimap == 0 || nimap == 1);
  		if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
  			xfs_daddr_t	block;
  
  			ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
  			block = imap.br_startblock;
  			mod = do_div(block, mp->m_sb.sb_rextsize);
  			if (mod)
  				startoffset_fsb += mp->m_sb.sb_rextsize - mod;
  		}
  		nimap = 1;
541d7d3c4   Lachlan McIlroy   [XFS] kill unness...
2490
  		error = xfs_bmapi(NULL, ip, endoffset_fsb - 1,
b4e9181e7   Christoph Hellwig   xfs: remove unuse...
2491
  			1, 0, NULL, 0, &imap, &nimap, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
  		if (error)
  			goto out_unlock_iolock;
  		ASSERT(nimap == 0 || nimap == 1);
  		if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
  			ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
  			mod++;
  			if (mod && (mod != mp->m_sb.sb_rextsize))
  				endoffset_fsb -= mod;
  		}
  	}
  	if ((done = (endoffset_fsb <= startoffset_fsb)))
  		/*
  		 * One contiguous piece to clear
  		 */
  		error = xfs_zero_remaining_bytes(ip, offset, offset + len - 1);
  	else {
  		/*
  		 * Some full blocks, possibly two pieces to clear
  		 */
  		if (offset < XFS_FSB_TO_B(mp, startoffset_fsb))
  			error = xfs_zero_remaining_bytes(ip, offset,
  				XFS_FSB_TO_B(mp, startoffset_fsb) - 1);
  		if (!error &&
  		    XFS_FSB_TO_B(mp, endoffset_fsb) < offset + len)
  			error = xfs_zero_remaining_bytes(ip,
  				XFS_FSB_TO_B(mp, endoffset_fsb),
  				offset + len - 1);
  	}
  
  	/*
  	 * free file space until done or until there is an error
  	 */
  	resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
  	while (!error && !done) {
  
  		/*
91ebecc74   David Chinner   [XFS] Allow punch...
2528
2529
2530
  		 * allocate and setup the transaction. Allow this
  		 * transaction to dip into the reserve blocks to ensure
  		 * the freeing of the space succeeds at ENOSPC.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2531
2532
  		 */
  		tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
91ebecc74   David Chinner   [XFS] Allow punch...
2533
  		tp->t_flags |= XFS_TRANS_RESERVE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
  		error = xfs_trans_reserve(tp,
  					  resblks,
  					  XFS_WRITE_LOG_RES(mp),
  					  0,
  					  XFS_TRANS_PERM_LOG_RES,
  					  XFS_WRITE_LOG_COUNT);
  
  		/*
  		 * check for running out of space
  		 */
  		if (error) {
  			/*
  			 * Free the transaction structure.
  			 */
  			ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp));
  			xfs_trans_cancel(tp, 0);
  			break;
  		}
  		xfs_ilock(ip, XFS_ILOCK_EXCL);
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2553
2554
2555
  		error = xfs_trans_reserve_quota(tp, mp,
  				ip->i_udquot, ip->i_gdquot,
  				resblks, 0, XFS_QMOPT_RES_REGBLKS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2556
2557
  		if (error)
  			goto error1;
898621d5a   Christoph Hellwig   xfs: simplify ino...
2558
  		xfs_trans_ijoin(tp, ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2559
2560
2561
2562
  
  		/*
  		 * issue the bunmapi() call to free the blocks
  		 */
9d87c3192   Eric Sandeen   [XFS] Remove the ...
2563
  		xfs_bmap_init(&free_list, &firstfsb);
541d7d3c4   Lachlan McIlroy   [XFS] kill unness...
2564
  		error = xfs_bunmapi(tp, ip, startoffset_fsb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2565
  				  endoffset_fsb - startoffset_fsb,
b4e9181e7   Christoph Hellwig   xfs: remove unuse...
2566
  				  0, 2, &firstfsb, &free_list, &done);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2567
2568
2569
2570
2571
2572
2573
  		if (error) {
  			goto error0;
  		}
  
  		/*
  		 * complete the transaction
  		 */
f7c99b6fc   Eric Sandeen   [XFS] Remove unus...
2574
  		error = xfs_bmap_finish(&tp, &free_list, &committed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2575
2576
2577
  		if (error) {
  			goto error0;
  		}
1c72bf900   Eric Sandeen   [XFS] The last ar...
2578
  		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
  		xfs_iunlock(ip, XFS_ILOCK_EXCL);
  	}
  
   out_unlock_iolock:
  	if (need_iolock)
  		xfs_iunlock(ip, XFS_IOLOCK_EXCL);
  	return error;
  
   error0:
  	xfs_bmap_cancel(&free_list);
   error1:
  	xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
  	xfs_iunlock(ip, need_iolock ? (XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL) :
  		    XFS_ILOCK_EXCL);
  	return error;
  }
  
  /*
   * xfs_change_file_space()
   *      This routine allocates or frees disk space for the given file.
   *      The user specified parameters are checked for alignment and size
   *      limitations.
   *
   * RETURNS:
   *       0 on success
   *      errno on error
   *
   */
  int
  xfs_change_file_space(
993386c19   Christoph Hellwig   [XFS] decontamina...
2609
  	xfs_inode_t	*ip,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2610
2611
2612
  	int		cmd,
  	xfs_flock64_t	*bf,
  	xfs_off_t	offset,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2613
2614
  	int		attr_flags)
  {
993386c19   Christoph Hellwig   [XFS] decontamina...
2615
  	xfs_mount_t	*mp = ip->i_mount;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2616
2617
2618
  	int		clrprealloc;
  	int		error;
  	xfs_fsize_t	fsize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2619
2620
2621
2622
  	int		setprealloc;
  	xfs_off_t	startoffset;
  	xfs_off_t	llen;
  	xfs_trans_t	*tp;
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
2623
  	struct iattr	iattr;
447223520   Dave Chinner   xfs: Introduce XF...
2624
  	int		prealloc_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2625

993386c19   Christoph Hellwig   [XFS] decontamina...
2626
  	if (!S_ISREG(ip->i_d.di_mode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2627
  		return XFS_ERROR(EINVAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2628
2629
2630
2631
2632
2633
2634
  	switch (bf->l_whence) {
  	case 0: /*SEEK_SET*/
  		break;
  	case 1: /*SEEK_CUR*/
  		bf->l_start += offset;
  		break;
  	case 2: /*SEEK_END*/
ba87ea699   Lachlan McIlroy   [XFS] Fix to prev...
2635
  		bf->l_start += ip->i_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
  		break;
  	default:
  		return XFS_ERROR(EINVAL);
  	}
  
  	llen = bf->l_len > 0 ? bf->l_len - 1 : bf->l_len;
  
  	if (   (bf->l_start < 0)
  	    || (bf->l_start > XFS_MAXIOFFSET(mp))
  	    || (bf->l_start + llen < 0)
  	    || (bf->l_start + llen > XFS_MAXIOFFSET(mp)))
  		return XFS_ERROR(EINVAL);
  
  	bf->l_whence = 0;
  
  	startoffset = bf->l_start;
ba87ea699   Lachlan McIlroy   [XFS] Fix to prev...
2652
  	fsize = ip->i_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
  
  	/*
  	 * XFS_IOC_RESVSP and XFS_IOC_UNRESVSP will reserve or unreserve
  	 * file space.
  	 * These calls do NOT zero the data space allocated to the file,
  	 * nor do they change the file size.
  	 *
  	 * XFS_IOC_ALLOCSP and XFS_IOC_FREESP will allocate and free file
  	 * space.
  	 * These calls cause the new file data to be zeroed and the file
  	 * size to be changed.
  	 */
  	setprealloc = clrprealloc = 0;
447223520   Dave Chinner   xfs: Introduce XF...
2666
  	prealloc_type = XFS_BMAPI_PREALLOC;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2667
2668
  
  	switch (cmd) {
447223520   Dave Chinner   xfs: Introduce XF...
2669
2670
2671
2672
  	case XFS_IOC_ZERO_RANGE:
  		prealloc_type |= XFS_BMAPI_CONVERT;
  		xfs_tosspages(ip, startoffset, startoffset + bf->l_len, 0);
  		/* FALLTHRU */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2673
2674
2675
  	case XFS_IOC_RESVSP:
  	case XFS_IOC_RESVSP64:
  		error = xfs_alloc_file_space(ip, startoffset, bf->l_len,
447223520   Dave Chinner   xfs: Introduce XF...
2676
  						prealloc_type, attr_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
  		if (error)
  			return error;
  		setprealloc = 1;
  		break;
  
  	case XFS_IOC_UNRESVSP:
  	case XFS_IOC_UNRESVSP64:
  		if ((error = xfs_free_file_space(ip, startoffset, bf->l_len,
  								attr_flags)))
  			return error;
  		break;
  
  	case XFS_IOC_ALLOCSP:
  	case XFS_IOC_ALLOCSP64:
  	case XFS_IOC_FREESP:
  	case XFS_IOC_FREESP64:
  		if (startoffset > fsize) {
  			error = xfs_alloc_file_space(ip, fsize,
  					startoffset - fsize, 0, attr_flags);
  			if (error)
  				break;
  		}
0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
2699
2700
  		iattr.ia_valid = ATTR_SIZE;
  		iattr.ia_size = startoffset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2701

ea5a3dc83   Christoph Hellwig   [XFS] kill sys_cred
2702
  		error = xfs_setattr(ip, &iattr, attr_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
  
  		if (error)
  			return error;
  
  		clrprealloc = 1;
  		break;
  
  	default:
  		ASSERT(0);
  		return XFS_ERROR(EINVAL);
  	}
  
  	/*
  	 * update the inode timestamp, mode, and prealloc flag bits
  	 */
  	tp = xfs_trans_alloc(mp, XFS_TRANS_WRITEID);
  
  	if ((error = xfs_trans_reserve(tp, 0, XFS_WRITEID_LOG_RES(mp),
  				      0, 0, 0))) {
  		/* ASSERT(0); */
  		xfs_trans_cancel(tp, 0);
  		return error;
  	}
  
  	xfs_ilock(ip, XFS_ILOCK_EXCL);
898621d5a   Christoph Hellwig   xfs: simplify ino...
2728
  	xfs_trans_ijoin(tp, ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2729

0f285c8a1   Christoph Hellwig   [XFS] Now that xf...
2730
  	if ((attr_flags & XFS_ATTR_DMI) == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
  		ip->i_d.di_mode &= ~S_ISUID;
  
  		/*
  		 * Note that we don't have to worry about mandatory
  		 * file locking being disabled here because we only
  		 * clear the S_ISGID bit if the Group execute bit is
  		 * on, but if it was on then mandatory locking wouldn't
  		 * have been enabled.
  		 */
  		if (ip->i_d.di_mode & S_IXGRP)
  			ip->i_d.di_mode &= ~S_ISGID;
dcd79a142   Dave Chinner   xfs: don't use vf...
2742
  		xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2743
2744
2745
2746
2747
2748
2749
  	}
  	if (setprealloc)
  		ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC;
  	else if (clrprealloc)
  		ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC;
  
  	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
828788974   Dave Chinner   xfs: preallocatio...
2750
2751
  	if (attr_flags & XFS_ATTR_SYNC)
  		xfs_trans_set_sync(tp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2752

1c72bf900   Eric Sandeen   [XFS] The last ar...
2753
  	error = xfs_trans_commit(tp, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2754
2755
2756
2757
2758
  
  	xfs_iunlock(ip, XFS_ILOCK_EXCL);
  
  	return error;
  }