diff options
Diffstat (limited to 'fs/xfs/xfs_vnodeops.c')
-rw-r--r-- | fs/xfs/xfs_vnodeops.c | 514 |
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 | ||
53 | int | ||
54 | xfs_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; |