aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_vnodeops.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_vnodeops.c')
-rw-r--r--fs/xfs/xfs_vnodeops.c514
1 files changed, 32 insertions, 482 deletions
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 619720705bc..d92419f0f2b 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -50,430 +50,6 @@
50#include "xfs_vnodeops.h" 50#include "xfs_vnodeops.h"
51#include "xfs_trace.h" 51#include "xfs_trace.h"
52 52
53int
54xfs_setattr(
55 struct xfs_inode *ip,
56 struct iattr *iattr,
57 int flags)
58{
59 xfs_mount_t *mp = ip->i_mount;
60 struct inode *inode = VFS_I(ip);
61 int mask = iattr->ia_valid;
62 xfs_trans_t *tp;
63 int code;
64 uint lock_flags;
65 uint commit_flags=0;
66 uid_t uid=0, iuid=0;
67 gid_t gid=0, igid=0;
68 struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2;
69 int need_iolock = 1;
70
71 trace_xfs_setattr(ip);
72
73 if (mp->m_flags & XFS_MOUNT_RDONLY)
74 return XFS_ERROR(EROFS);
75
76 if (XFS_FORCED_SHUTDOWN(mp))
77 return XFS_ERROR(EIO);
78
79 code = -inode_change_ok(inode, iattr);
80 if (code)
81 return code;
82
83 olddquot1 = olddquot2 = NULL;
84 udqp = gdqp = NULL;
85
86 /*
87 * If disk quotas is on, we make sure that the dquots do exist on disk,
88 * before we start any other transactions. Trying to do this later
89 * is messy. We don't care to take a readlock to look at the ids
90 * in inode here, because we can't hold it across the trans_reserve.
91 * If the IDs do change before we take the ilock, we're covered
92 * because the i_*dquot fields will get updated anyway.
93 */
94 if (XFS_IS_QUOTA_ON(mp) && (mask & (ATTR_UID|ATTR_GID))) {
95 uint qflags = 0;
96
97 if ((mask & ATTR_UID) && XFS_IS_UQUOTA_ON(mp)) {
98 uid = iattr->ia_uid;
99 qflags |= XFS_QMOPT_UQUOTA;
100 } else {
101 uid = ip->i_d.di_uid;
102 }
103 if ((mask & ATTR_GID) && XFS_IS_GQUOTA_ON(mp)) {
104 gid = iattr->ia_gid;
105 qflags |= XFS_QMOPT_GQUOTA;
106 } else {
107 gid = ip->i_d.di_gid;
108 }
109
110 /*
111 * We take a reference when we initialize udqp and gdqp,
112 * so it is important that we never blindly double trip on
113 * the same variable. See xfs_create() for an example.
114 */
115 ASSERT(udqp == NULL);
116 ASSERT(gdqp == NULL);
117 code = xfs_qm_vop_dqalloc(ip, uid, gid, xfs_get_projid(ip),
118 qflags, &udqp, &gdqp);
119 if (code)
120 return code;
121 }
122
123 /*
124 * For the other attributes, we acquire the inode lock and
125 * first do an error checking pass.
126 */
127 tp = NULL;
128 lock_flags = XFS_ILOCK_EXCL;
129 if (flags & XFS_ATTR_NOLOCK)
130 need_iolock = 0;
131 if (!(mask & ATTR_SIZE)) {
132 tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
133 commit_flags = 0;
134 code = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp),
135 0, 0, 0);
136 if (code) {
137 lock_flags = 0;
138 goto error_return;
139 }
140 } else {
141 if (need_iolock)
142 lock_flags |= XFS_IOLOCK_EXCL;
143 }
144
145 xfs_ilock(ip, lock_flags);
146
147 /*
148 * Change file ownership. Must be the owner or privileged.
149 */
150 if (mask & (ATTR_UID|ATTR_GID)) {
151 /*
152 * These IDs could have changed since we last looked at them.
153 * But, we're assured that if the ownership did change
154 * while we didn't have the inode locked, inode's dquot(s)
155 * would have changed also.
156 */
157 iuid = ip->i_d.di_uid;
158 igid = ip->i_d.di_gid;
159 gid = (mask & ATTR_GID) ? iattr->ia_gid : igid;
160 uid = (mask & ATTR_UID) ? iattr->ia_uid : iuid;
161
162 /*
163 * Do a quota reservation only if uid/gid is actually
164 * going to change.
165 */
166 if (XFS_IS_QUOTA_RUNNING(mp) &&
167 ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) ||
168 (XFS_IS_GQUOTA_ON(mp) && igid != gid))) {
169 ASSERT(tp);
170 code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
171 capable(CAP_FOWNER) ?
172 XFS_QMOPT_FORCE_RES : 0);
173 if (code) /* out of quota */
174 goto error_return;
175 }
176 }
177
178 /*
179 * Truncate file. Must have write permission and not be a directory.
180 */
181 if (mask & ATTR_SIZE) {
182 /* Short circuit the truncate case for zero length files */
183 if (iattr->ia_size == 0 &&
184 ip->i_size == 0 && ip->i_d.di_nextents == 0) {
185 xfs_iunlock(ip, XFS_ILOCK_EXCL);
186 lock_flags &= ~XFS_ILOCK_EXCL;
187 if (mask & ATTR_CTIME) {
188 inode->i_mtime = inode->i_ctime =
189 current_fs_time(inode->i_sb);
190 xfs_mark_inode_dirty_sync(ip);
191 }
192 code = 0;
193 goto error_return;
194 }
195
196 if (S_ISDIR(ip->i_d.di_mode)) {
197 code = XFS_ERROR(EISDIR);
198 goto error_return;
199 } else if (!S_ISREG(ip->i_d.di_mode)) {
200 code = XFS_ERROR(EINVAL);
201 goto error_return;
202 }
203
204 /*
205 * Make sure that the dquots are attached to the inode.
206 */
207 code = xfs_qm_dqattach_locked(ip, 0);
208 if (code)
209 goto error_return;
210
211 /*
212 * Now we can make the changes. Before we join the inode
213 * to the transaction, if ATTR_SIZE is set then take care of
214 * the part of the truncation that must be done without the
215 * inode lock. This needs to be done before joining the inode
216 * to the transaction, because the inode cannot be unlocked
217 * once it is a part of the transaction.
218 */
219 if (iattr->ia_size > ip->i_size) {
220 /*
221 * Do the first part of growing a file: zero any data
222 * in the last block that is beyond the old EOF. We
223 * need to do this before the inode is joined to the
224 * transaction to modify the i_size.
225 */
226 code = xfs_zero_eof(ip, iattr->ia_size, ip->i_size);
227 if (code)
228 goto error_return;
229 }
230 xfs_iunlock(ip, XFS_ILOCK_EXCL);
231 lock_flags &= ~XFS_ILOCK_EXCL;
232
233 /*
234 * We are going to log the inode size change in this
235 * transaction so any previous writes that are beyond the on
236 * disk EOF and the new EOF that have not been written out need
237 * to be written here. If we do not write the data out, we
238 * expose ourselves to the null files problem.
239 *
240 * Only flush from the on disk size to the smaller of the in
241 * memory file size or the new size as that's the range we
242 * really care about here and prevents waiting for other data
243 * not within the range we care about here.
244 */
245 if (ip->i_size != ip->i_d.di_size &&
246 iattr->ia_size > ip->i_d.di_size) {
247 code = xfs_flush_pages(ip,
248 ip->i_d.di_size, iattr->ia_size,
249 XBF_ASYNC, FI_NONE);
250 if (code)
251 goto error_return;
252 }
253
254 /* wait for all I/O to complete */
255 xfs_ioend_wait(ip);
256
257 code = -block_truncate_page(inode->i_mapping, iattr->ia_size,
258 xfs_get_blocks);
259 if (code)
260 goto error_return;
261
262 tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE);
263 code = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
264 XFS_TRANS_PERM_LOG_RES,
265 XFS_ITRUNCATE_LOG_COUNT);
266 if (code)
267 goto error_return;
268
269 truncate_setsize(inode, iattr->ia_size);
270
271 commit_flags = XFS_TRANS_RELEASE_LOG_RES;
272 lock_flags |= XFS_ILOCK_EXCL;
273
274 xfs_ilock(ip, XFS_ILOCK_EXCL);
275
276 xfs_trans_ijoin(tp, ip);
277
278 /*
279 * Only change the c/mtime if we are changing the size
280 * or we are explicitly asked to change it. This handles
281 * the semantic difference between truncate() and ftruncate()
282 * as implemented in the VFS.
283 *
284 * The regular truncate() case without ATTR_CTIME and ATTR_MTIME
285 * is a special case where we need to update the times despite
286 * not having these flags set. For all other operations the
287 * VFS set these flags explicitly if it wants a timestamp
288 * update.
289 */
290 if (iattr->ia_size != ip->i_size &&
291 (!(mask & (ATTR_CTIME | ATTR_MTIME)))) {
292 iattr->ia_ctime = iattr->ia_mtime =
293 current_fs_time(inode->i_sb);
294 mask |= ATTR_CTIME | ATTR_MTIME;
295 }
296
297 if (iattr->ia_size > ip->i_size) {
298 ip->i_d.di_size = iattr->ia_size;
299 ip->i_size = iattr->ia_size;
300 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
301 } else if (iattr->ia_size <= ip->i_size ||
302 (iattr->ia_size == 0 && ip->i_d.di_nextents)) {
303 /*
304 * signal a sync transaction unless
305 * we're truncating an already unlinked
306 * file on a wsync filesystem
307 */
308 code = xfs_itruncate_finish(&tp, ip, iattr->ia_size,
309 XFS_DATA_FORK,
310 ((ip->i_d.di_nlink != 0 ||
311 !(mp->m_flags & XFS_MOUNT_WSYNC))
312 ? 1 : 0));
313 if (code)
314 goto abort_return;
315 /*
316 * Truncated "down", so we're removing references
317 * to old data here - if we now delay flushing for
318 * a long time, we expose ourselves unduly to the
319 * notorious NULL files problem. So, we mark this
320 * vnode and flush it when the file is closed, and
321 * do not wait the usual (long) time for writeout.
322 */
323 xfs_iflags_set(ip, XFS_ITRUNCATED);
324 }
325 } else if (tp) {
326 xfs_trans_ijoin(tp, ip);
327 }
328
329 /*
330 * Change file ownership. Must be the owner or privileged.
331 */
332 if (mask & (ATTR_UID|ATTR_GID)) {
333 /*
334 * CAP_FSETID overrides the following restrictions:
335 *
336 * The set-user-ID and set-group-ID bits of a file will be
337 * cleared upon successful return from chown()
338 */
339 if ((ip->i_d.di_mode & (S_ISUID|S_ISGID)) &&
340 !capable(CAP_FSETID)) {
341 ip->i_d.di_mode &= ~(S_ISUID|S_ISGID);
342 }
343
344 /*
345 * Change the ownerships and register quota modifications
346 * in the transaction.
347 */
348 if (iuid != uid) {
349 if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_UQUOTA_ON(mp)) {
350 ASSERT(mask & ATTR_UID);
351 ASSERT(udqp);
352 olddquot1 = xfs_qm_vop_chown(tp, ip,
353 &ip->i_udquot, udqp);
354 }
355 ip->i_d.di_uid = uid;
356 inode->i_uid = uid;
357 }
358 if (igid != gid) {
359 if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_GQUOTA_ON(mp)) {
360 ASSERT(!XFS_IS_PQUOTA_ON(mp));
361 ASSERT(mask & ATTR_GID);
362 ASSERT(gdqp);
363 olddquot2 = xfs_qm_vop_chown(tp, ip,
364 &ip->i_gdquot, gdqp);
365 }
366 ip->i_d.di_gid = gid;
367 inode->i_gid = gid;
368 }
369 }
370
371 /*
372 * Change file access modes.
373 */
374 if (mask & ATTR_MODE) {
375 umode_t mode = iattr->ia_mode;
376
377 if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
378 mode &= ~S_ISGID;
379
380 ip->i_d.di_mode &= S_IFMT;
381 ip->i_d.di_mode |= mode & ~S_IFMT;
382
383 inode->i_mode &= S_IFMT;
384 inode->i_mode |= mode & ~S_IFMT;
385 }
386
387 /*
388 * Change file access or modified times.
389 */
390 if (mask & ATTR_ATIME) {
391 inode->i_atime = iattr->ia_atime;
392 ip->i_d.di_atime.t_sec = iattr->ia_atime.tv_sec;
393 ip->i_d.di_atime.t_nsec = iattr->ia_atime.tv_nsec;
394 ip->i_update_core = 1;
395 }
396 if (mask & ATTR_CTIME) {
397 inode->i_ctime = iattr->ia_ctime;
398 ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec;
399 ip->i_d.di_ctime.t_nsec = iattr->ia_ctime.tv_nsec;
400 ip->i_update_core = 1;
401 }
402 if (mask & ATTR_MTIME) {
403 inode->i_mtime = iattr->ia_mtime;
404 ip->i_d.di_mtime.t_sec = iattr->ia_mtime.tv_sec;
405 ip->i_d.di_mtime.t_nsec = iattr->ia_mtime.tv_nsec;
406 ip->i_update_core = 1;
407 }
408
409 /*
410 * And finally, log the inode core if any attribute in it
411 * has been changed.
412 */
413 if (mask & (ATTR_UID|ATTR_GID|ATTR_MODE|
414 ATTR_ATIME|ATTR_CTIME|ATTR_MTIME))
415 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
416
417 XFS_STATS_INC(xs_ig_attrchg);
418
419 /*
420 * If this is a synchronous mount, make sure that the
421 * transaction goes to disk before returning to the user.
422 * This is slightly sub-optimal in that truncates require
423 * two sync transactions instead of one for wsync filesystems.
424 * One for the truncate and one for the timestamps since we
425 * don't want to change the timestamps unless we're sure the
426 * truncate worked. Truncates are less than 1% of the laddis
427 * mix so this probably isn't worth the trouble to optimize.
428 */
429 code = 0;
430 if (mp->m_flags & XFS_MOUNT_WSYNC)
431 xfs_trans_set_sync(tp);
432
433 code = xfs_trans_commit(tp, commit_flags);
434
435 xfs_iunlock(ip, lock_flags);
436
437 /*
438 * Release any dquot(s) the inode had kept before chown.
439 */
440 xfs_qm_dqrele(olddquot1);
441 xfs_qm_dqrele(olddquot2);
442 xfs_qm_dqrele(udqp);
443 xfs_qm_dqrele(gdqp);
444
445 if (code)
446 return code;
447
448 /*
449 * XXX(hch): Updating the ACL entries is not atomic vs the i_mode
450 * update. We could avoid this with linked transactions
451 * and passing down the transaction pointer all the way
452 * to attr_set. No previous user of the generic
453 * Posix ACL code seems to care about this issue either.
454 */
455 if ((mask & ATTR_MODE) && !(flags & XFS_ATTR_NOACL)) {
456 code = -xfs_acl_chmod(inode);
457 if (code)
458 return XFS_ERROR(code);
459 }
460
461 return 0;
462
463 abort_return:
464 commit_flags |= XFS_TRANS_ABORT;
465 error_return:
466 xfs_qm_dqrele(udqp);
467 xfs_qm_dqrele(gdqp);
468 if (tp) {
469 xfs_trans_cancel(tp, commit_flags);
470 }
471 if (lock_flags != 0) {
472 xfs_iunlock(ip, lock_flags);
473 }
474 return code;
475}
476
477/* 53/*
478 * The maximum pathlen is 1024 bytes. Since the minimum file system 54 * The maximum pathlen is 1024 bytes. Since the minimum file system
479 * blocksize is 512 bytes, we can get a max of 2 extents back from 55 * blocksize is 512 bytes, we can get a max of 2 extents back from
@@ -507,7 +83,9 @@ xfs_readlink_bmap(
507 83
508 bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 84 bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt),
509 XBF_LOCK | XBF_MAPPED | XBF_DONT_BLOCK); 85 XBF_LOCK | XBF_MAPPED | XBF_DONT_BLOCK);
510 error = XFS_BUF_GETERROR(bp); 86 if (!bp)
87 return XFS_ERROR(ENOMEM);
88 error = bp->b_error;
511 if (error) { 89 if (error) {
512 xfs_ioerror_alert("xfs_readlink", 90 xfs_ioerror_alert("xfs_readlink",
513 ip->i_mount, bp, XFS_BUF_ADDR(bp)); 91 ip->i_mount, bp, XFS_BUF_ADDR(bp));
@@ -518,7 +96,7 @@ xfs_readlink_bmap(
518 byte_cnt = pathlen; 96 byte_cnt = pathlen;
519 pathlen -= byte_cnt; 97 pathlen -= byte_cnt;
520 98
521 memcpy(link, XFS_BUF_PTR(bp), byte_cnt); 99 memcpy(link, bp->b_addr, byte_cnt);
522 xfs_buf_relse(bp); 100 xfs_buf_relse(bp);
523 } 101 }
524 102
@@ -535,7 +113,7 @@ xfs_readlink(
535 char *link) 113 char *link)
536{ 114{
537 xfs_mount_t *mp = ip->i_mount; 115 xfs_mount_t *mp = ip->i_mount;
538 int pathlen; 116 xfs_fsize_t pathlen;
539 int error = 0; 117 int error = 0;
540 118
541 trace_xfs_readlink(ip); 119 trace_xfs_readlink(ip);
@@ -545,13 +123,20 @@ xfs_readlink(
545 123
546 xfs_ilock(ip, XFS_ILOCK_SHARED); 124 xfs_ilock(ip, XFS_ILOCK_SHARED);
547 125
548 ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFLNK);
549 ASSERT(ip->i_d.di_size <= MAXPATHLEN);
550
551 pathlen = ip->i_d.di_size; 126 pathlen = ip->i_d.di_size;
552 if (!pathlen) 127 if (!pathlen)
553 goto out; 128 goto out;
554 129
130 if (pathlen < 0 || pathlen > MAXPATHLEN) {
131 xfs_alert(mp, "%s: inode (%llu) bad symlink length (%lld)",
132 __func__, (unsigned long long) ip->i_ino,
133 (long long) pathlen);
134 ASSERT(0);
135 error = XFS_ERROR(EFSCORRUPTED);
136 goto out;
137 }
138
139
555 if (ip->i_df.if_flags & XFS_IFINLINE) { 140 if (ip->i_df.if_flags & XFS_IFINLINE) {
556 memcpy(link, ip->i_df.if_u1.if_data, pathlen); 141 memcpy(link, ip->i_df.if_u1.if_data, pathlen);
557 link[pathlen] = '\0'; 142 link[pathlen] = '\0';
@@ -621,13 +206,6 @@ xfs_free_eofblocks(
621 */ 206 */
622 tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); 207 tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
623 208
624 /*
625 * Do the xfs_itruncate_start() call before
626 * reserving any log space because
627 * itruncate_start will call into the buffer
628 * cache and we can't
629 * do that within a transaction.
630 */
631 if (flags & XFS_FREE_EOF_TRYLOCK) { 209 if (flags & XFS_FREE_EOF_TRYLOCK) {
632 if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) { 210 if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) {
633 xfs_trans_cancel(tp, 0); 211 xfs_trans_cancel(tp, 0);
@@ -636,13 +214,6 @@ xfs_free_eofblocks(
636 } else { 214 } else {
637 xfs_ilock(ip, XFS_IOLOCK_EXCL); 215 xfs_ilock(ip, XFS_IOLOCK_EXCL);
638 } 216 }
639 error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE,
640 ip->i_size);
641 if (error) {
642 xfs_trans_cancel(tp, 0);
643 xfs_iunlock(ip, XFS_IOLOCK_EXCL);
644 return error;
645 }
646 217
647 error = xfs_trans_reserve(tp, 0, 218 error = xfs_trans_reserve(tp, 0,
648 XFS_ITRUNCATE_LOG_RES(mp), 219 XFS_ITRUNCATE_LOG_RES(mp),
@@ -658,15 +229,12 @@ xfs_free_eofblocks(
658 xfs_ilock(ip, XFS_ILOCK_EXCL); 229 xfs_ilock(ip, XFS_ILOCK_EXCL);
659 xfs_trans_ijoin(tp, ip); 230 xfs_trans_ijoin(tp, ip);
660 231
661 error = xfs_itruncate_finish(&tp, ip, 232 error = xfs_itruncate_data(&tp, ip, ip->i_size);
662 ip->i_size,
663 XFS_DATA_FORK,
664 0);
665 /*
666 * If we get an error at this point we
667 * simply don't bother truncating the file.
668 */
669 if (error) { 233 if (error) {
234 /*
235 * If we get an error at this point we simply don't
236 * bother truncating the file.
237 */
670 xfs_trans_cancel(tp, 238 xfs_trans_cancel(tp,
671 (XFS_TRANS_RELEASE_LOG_RES | 239 (XFS_TRANS_RELEASE_LOG_RES |
672 XFS_TRANS_ABORT)); 240 XFS_TRANS_ABORT));
@@ -970,7 +538,7 @@ xfs_release(
970 if (ip->i_d.di_nlink == 0) 538 if (ip->i_d.di_nlink == 0)
971 return 0; 539 return 0;
972 540
973 if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && 541 if ((S_ISREG(ip->i_d.di_mode) &&
974 ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 || 542 ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 ||
975 ip->i_delayed_blks > 0)) && 543 ip->i_delayed_blks > 0)) &&
976 (ip->i_df.if_flags & XFS_IFEXTENTS)) && 544 (ip->i_df.if_flags & XFS_IFEXTENTS)) &&
@@ -1051,7 +619,7 @@ xfs_inactive(
1051 truncate = ((ip->i_d.di_nlink == 0) && 619 truncate = ((ip->i_d.di_nlink == 0) &&
1052 ((ip->i_d.di_size != 0) || (ip->i_size != 0) || 620 ((ip->i_d.di_size != 0) || (ip->i_size != 0) ||
1053 (ip->i_d.di_nextents > 0) || (ip->i_delayed_blks > 0)) && 621 (ip->i_d.di_nextents > 0) || (ip->i_delayed_blks > 0)) &&
1054 ((ip->i_d.di_mode & S_IFMT) == S_IFREG)); 622 S_ISREG(ip->i_d.di_mode));
1055 623
1056 mp = ip->i_mount; 624 mp = ip->i_mount;
1057 625
@@ -1062,7 +630,7 @@ xfs_inactive(
1062 goto out; 630 goto out;
1063 631
1064 if (ip->i_d.di_nlink != 0) { 632 if (ip->i_d.di_nlink != 0) {
1065 if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && 633 if ((S_ISREG(ip->i_d.di_mode) &&
1066 ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 || 634 ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 ||
1067 ip->i_delayed_blks > 0)) && 635 ip->i_delayed_blks > 0)) &&
1068 (ip->i_df.if_flags & XFS_IFEXTENTS) && 636 (ip->i_df.if_flags & XFS_IFEXTENTS) &&
@@ -1084,20 +652,9 @@ xfs_inactive(
1084 652
1085 tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); 653 tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
1086 if (truncate) { 654 if (truncate) {
1087 /*
1088 * Do the xfs_itruncate_start() call before
1089 * reserving any log space because itruncate_start
1090 * will call into the buffer cache and we can't
1091 * do that within a transaction.
1092 */
1093 xfs_ilock(ip, XFS_IOLOCK_EXCL); 655 xfs_ilock(ip, XFS_IOLOCK_EXCL);
1094 656
1095 error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0); 657 xfs_ioend_wait(ip);
1096 if (error) {
1097 xfs_trans_cancel(tp, 0);
1098 xfs_iunlock(ip, XFS_IOLOCK_EXCL);
1099 return VN_INACTIVE_CACHE;
1100 }
1101 658
1102 error = xfs_trans_reserve(tp, 0, 659 error = xfs_trans_reserve(tp, 0,
1103 XFS_ITRUNCATE_LOG_RES(mp), 660 XFS_ITRUNCATE_LOG_RES(mp),
@@ -1114,23 +671,14 @@ xfs_inactive(
1114 xfs_ilock(ip, XFS_ILOCK_EXCL); 671 xfs_ilock(ip, XFS_ILOCK_EXCL);
1115 xfs_trans_ijoin(tp, ip); 672 xfs_trans_ijoin(tp, ip);
1116 673
1117 /* 674 error = xfs_itruncate_data(&tp, ip, 0);
1118 * normally, we have to run xfs_itruncate_finish sync.
1119 * But if filesystem is wsync and we're in the inactive
1120 * path, then we know that nlink == 0, and that the
1121 * xaction that made nlink == 0 is permanently committed
1122 * since xfs_remove runs as a synchronous transaction.
1123 */
1124 error = xfs_itruncate_finish(&tp, ip, 0, XFS_DATA_FORK,
1125 (!(mp->m_flags & XFS_MOUNT_WSYNC) ? 1 : 0));
1126
1127 if (error) { 675 if (error) {
1128 xfs_trans_cancel(tp, 676 xfs_trans_cancel(tp,
1129 XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); 677 XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
1130 xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); 678 xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
1131 return VN_INACTIVE_CACHE; 679 return VN_INACTIVE_CACHE;
1132 } 680 }
1133 } else if ((ip->i_d.di_mode & S_IFMT) == S_IFLNK) { 681 } else if (S_ISLNK(ip->i_d.di_mode)) {
1134 682
1135 /* 683 /*
1136 * If we get an error while cleaning up a 684 * If we get an error while cleaning up a
@@ -2109,13 +1657,13 @@ xfs_symlink(
2109 byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); 1657 byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
2110 bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, 1658 bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
2111 BTOBB(byte_cnt), 0); 1659 BTOBB(byte_cnt), 0);
2112 ASSERT(bp && !XFS_BUF_GETERROR(bp)); 1660 ASSERT(!xfs_buf_geterror(bp));
2113 if (pathlen < byte_cnt) { 1661 if (pathlen < byte_cnt) {
2114 byte_cnt = pathlen; 1662 byte_cnt = pathlen;
2115 } 1663 }
2116 pathlen -= byte_cnt; 1664 pathlen -= byte_cnt;
2117 1665
2118 memcpy(XFS_BUF_PTR(bp), cur_chunk, byte_cnt); 1666 memcpy(bp->b_addr, cur_chunk, byte_cnt);
2119 cur_chunk += byte_cnt; 1667 cur_chunk += byte_cnt;
2120 1668
2121 xfs_trans_log_buf(tp, bp, 0, byte_cnt - 1); 1669 xfs_trans_log_buf(tp, bp, 0, byte_cnt - 1);
@@ -2430,6 +1978,8 @@ xfs_zero_remaining_bytes(
2430 if (!bp) 1978 if (!bp)
2431 return XFS_ERROR(ENOMEM); 1979 return XFS_ERROR(ENOMEM);
2432 1980
1981 xfs_buf_unlock(bp);
1982
2433 for (offset = startoff; offset <= endoff; offset = lastoffset + 1) { 1983 for (offset = startoff; offset <= endoff; offset = lastoffset + 1) {
2434 offset_fsb = XFS_B_TO_FSBT(mp, offset); 1984 offset_fsb = XFS_B_TO_FSBT(mp, offset);
2435 nimap = 1; 1985 nimap = 1;
@@ -2458,7 +2008,7 @@ xfs_zero_remaining_bytes(
2458 mp, bp, XFS_BUF_ADDR(bp)); 2008 mp, bp, XFS_BUF_ADDR(bp));
2459 break; 2009 break;
2460 } 2010 }
2461 memset(XFS_BUF_PTR(bp) + 2011 memset(bp->b_addr +
2462 (offset - XFS_FSB_TO_B(mp, imap.br_startoff)), 2012 (offset - XFS_FSB_TO_B(mp, imap.br_startoff)),
2463 0, lastoffset - offset + 1); 2013 0, lastoffset - offset + 1);
2464 XFS_BUF_UNDONE(bp); 2014 XFS_BUF_UNDONE(bp);
@@ -2784,7 +2334,7 @@ xfs_change_file_space(
2784 iattr.ia_valid = ATTR_SIZE; 2334 iattr.ia_valid = ATTR_SIZE;
2785 iattr.ia_size = startoffset; 2335 iattr.ia_size = startoffset;
2786 2336
2787 error = xfs_setattr(ip, &iattr, attr_flags); 2337 error = xfs_setattr_size(ip, &iattr, attr_flags);
2788 2338
2789 if (error) 2339 if (error)
2790 return error; 2340 return error;