diff options
Diffstat (limited to 'fs/xfs/xfs_vnodeops.c')
-rw-r--r-- | fs/xfs/xfs_vnodeops.c | 354 |
1 files changed, 58 insertions, 296 deletions
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 8b6812f66a1..f07bf8768c3 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
@@ -54,33 +54,10 @@ | |||
54 | #include "xfs_vnodeops.h" | 54 | #include "xfs_vnodeops.h" |
55 | 55 | ||
56 | int | 56 | int |
57 | xfs_open( | ||
58 | xfs_inode_t *ip) | ||
59 | { | ||
60 | int mode; | ||
61 | |||
62 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) | ||
63 | return XFS_ERROR(EIO); | ||
64 | |||
65 | /* | ||
66 | * If it's a directory with any blocks, read-ahead block 0 | ||
67 | * as we're almost certain to have the next operation be a read there. | ||
68 | */ | ||
69 | if (S_ISDIR(ip->i_d.di_mode) && ip->i_d.di_nextents > 0) { | ||
70 | mode = xfs_ilock_map_shared(ip); | ||
71 | if (ip->i_d.di_nextents > 0) | ||
72 | (void)xfs_da_reada_buf(NULL, ip, 0, XFS_DATA_FORK); | ||
73 | xfs_iunlock(ip, mode); | ||
74 | } | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | int | ||
79 | xfs_setattr( | 57 | xfs_setattr( |
80 | struct xfs_inode *ip, | 58 | struct xfs_inode *ip, |
81 | struct iattr *iattr, | 59 | struct iattr *iattr, |
82 | int flags, | 60 | int flags) |
83 | cred_t *credp) | ||
84 | { | 61 | { |
85 | xfs_mount_t *mp = ip->i_mount; | 62 | xfs_mount_t *mp = ip->i_mount; |
86 | struct inode *inode = VFS_I(ip); | 63 | struct inode *inode = VFS_I(ip); |
@@ -93,7 +70,6 @@ xfs_setattr( | |||
93 | gid_t gid=0, igid=0; | 70 | gid_t gid=0, igid=0; |
94 | int timeflags = 0; | 71 | int timeflags = 0; |
95 | struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; | 72 | struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; |
96 | int file_owner; | ||
97 | int need_iolock = 1; | 73 | int need_iolock = 1; |
98 | 74 | ||
99 | xfs_itrace_entry(ip); | 75 | xfs_itrace_entry(ip); |
@@ -104,6 +80,10 @@ xfs_setattr( | |||
104 | if (XFS_FORCED_SHUTDOWN(mp)) | 80 | if (XFS_FORCED_SHUTDOWN(mp)) |
105 | return XFS_ERROR(EIO); | 81 | return XFS_ERROR(EIO); |
106 | 82 | ||
83 | code = -inode_change_ok(inode, iattr); | ||
84 | if (code) | ||
85 | return code; | ||
86 | |||
107 | olddquot1 = olddquot2 = NULL; | 87 | olddquot1 = olddquot2 = NULL; |
108 | udqp = gdqp = NULL; | 88 | udqp = gdqp = NULL; |
109 | 89 | ||
@@ -181,62 +161,8 @@ xfs_setattr( | |||
181 | 161 | ||
182 | xfs_ilock(ip, lock_flags); | 162 | xfs_ilock(ip, lock_flags); |
183 | 163 | ||
184 | /* boolean: are we the file owner? */ | ||
185 | file_owner = (current_fsuid() == ip->i_d.di_uid); | ||
186 | |||
187 | /* | ||
188 | * Change various properties of a file. | ||
189 | * Only the owner or users with CAP_FOWNER | ||
190 | * capability may do these things. | ||
191 | */ | ||
192 | if (mask & (ATTR_MODE|ATTR_UID|ATTR_GID)) { | ||
193 | /* | ||
194 | * CAP_FOWNER overrides the following restrictions: | ||
195 | * | ||
196 | * The user ID of the calling process must be equal | ||
197 | * to the file owner ID, except in cases where the | ||
198 | * CAP_FSETID capability is applicable. | ||
199 | */ | ||
200 | if (!file_owner && !capable(CAP_FOWNER)) { | ||
201 | code = XFS_ERROR(EPERM); | ||
202 | goto error_return; | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * CAP_FSETID overrides the following restrictions: | ||
207 | * | ||
208 | * The effective user ID of the calling process shall match | ||
209 | * the file owner when setting the set-user-ID and | ||
210 | * set-group-ID bits on that file. | ||
211 | * | ||
212 | * The effective group ID or one of the supplementary group | ||
213 | * IDs of the calling process shall match the group owner of | ||
214 | * the file when setting the set-group-ID bit on that file | ||
215 | */ | ||
216 | if (mask & ATTR_MODE) { | ||
217 | mode_t m = 0; | ||
218 | |||
219 | if ((iattr->ia_mode & S_ISUID) && !file_owner) | ||
220 | m |= S_ISUID; | ||
221 | if ((iattr->ia_mode & S_ISGID) && | ||
222 | !in_group_p((gid_t)ip->i_d.di_gid)) | ||
223 | m |= S_ISGID; | ||
224 | #if 0 | ||
225 | /* Linux allows this, Irix doesn't. */ | ||
226 | if ((iattr->ia_mode & S_ISVTX) && !S_ISDIR(ip->i_d.di_mode)) | ||
227 | m |= S_ISVTX; | ||
228 | #endif | ||
229 | if (m && !capable(CAP_FSETID)) | ||
230 | iattr->ia_mode &= ~m; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | /* | 164 | /* |
235 | * Change file ownership. Must be the owner or privileged. | 165 | * Change file ownership. Must be the owner or privileged. |
236 | * If the system was configured with the "restricted_chown" | ||
237 | * option, the owner is not permitted to give away the file, | ||
238 | * and can change the group id only to a group of which he | ||
239 | * or she is a member. | ||
240 | */ | 166 | */ |
241 | if (mask & (ATTR_UID|ATTR_GID)) { | 167 | if (mask & (ATTR_UID|ATTR_GID)) { |
242 | /* | 168 | /* |
@@ -251,23 +177,6 @@ xfs_setattr( | |||
251 | uid = (mask & ATTR_UID) ? iattr->ia_uid : iuid; | 177 | uid = (mask & ATTR_UID) ? iattr->ia_uid : iuid; |
252 | 178 | ||
253 | /* | 179 | /* |
254 | * CAP_CHOWN overrides the following restrictions: | ||
255 | * | ||
256 | * If _POSIX_CHOWN_RESTRICTED is defined, this capability | ||
257 | * shall override the restriction that a process cannot | ||
258 | * change the user ID of a file it owns and the restriction | ||
259 | * that the group ID supplied to the chown() function | ||
260 | * shall be equal to either the group ID or one of the | ||
261 | * supplementary group IDs of the calling process. | ||
262 | */ | ||
263 | if (restricted_chown && | ||
264 | (iuid != uid || (igid != gid && | ||
265 | !in_group_p((gid_t)gid))) && | ||
266 | !capable(CAP_CHOWN)) { | ||
267 | code = XFS_ERROR(EPERM); | ||
268 | goto error_return; | ||
269 | } | ||
270 | /* | ||
271 | * Do a quota reservation only if uid/gid is actually | 180 | * Do a quota reservation only if uid/gid is actually |
272 | * going to change. | 181 | * going to change. |
273 | */ | 182 | */ |
@@ -304,36 +213,22 @@ xfs_setattr( | |||
304 | code = XFS_ERROR(EINVAL); | 213 | code = XFS_ERROR(EINVAL); |
305 | goto error_return; | 214 | goto error_return; |
306 | } | 215 | } |
216 | |||
307 | /* | 217 | /* |
308 | * Make sure that the dquots are attached to the inode. | 218 | * Make sure that the dquots are attached to the inode. |
309 | */ | 219 | */ |
310 | if ((code = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED))) | 220 | code = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED); |
221 | if (code) | ||
311 | goto error_return; | 222 | goto error_return; |
312 | } | ||
313 | |||
314 | /* | ||
315 | * Change file access or modified times. | ||
316 | */ | ||
317 | if (mask & (ATTR_ATIME|ATTR_MTIME)) { | ||
318 | if (!file_owner) { | ||
319 | if ((mask & (ATTR_MTIME_SET|ATTR_ATIME_SET)) && | ||
320 | !capable(CAP_FOWNER)) { | ||
321 | code = XFS_ERROR(EPERM); | ||
322 | goto error_return; | ||
323 | } | ||
324 | } | ||
325 | } | ||
326 | 223 | ||
327 | /* | 224 | /* |
328 | * Now we can make the changes. Before we join the inode | 225 | * Now we can make the changes. Before we join the inode |
329 | * to the transaction, if ATTR_SIZE is set then take care of | 226 | * to the transaction, if ATTR_SIZE is set then take care of |
330 | * the part of the truncation that must be done without the | 227 | * the part of the truncation that must be done without the |
331 | * inode lock. This needs to be done before joining the inode | 228 | * inode lock. This needs to be done before joining the inode |
332 | * to the transaction, because the inode cannot be unlocked | 229 | * to the transaction, because the inode cannot be unlocked |
333 | * once it is a part of the transaction. | 230 | * once it is a part of the transaction. |
334 | */ | 231 | */ |
335 | if (mask & ATTR_SIZE) { | ||
336 | code = 0; | ||
337 | if (iattr->ia_size > ip->i_size) { | 232 | if (iattr->ia_size > ip->i_size) { |
338 | /* | 233 | /* |
339 | * Do the first part of growing a file: zero any data | 234 | * Do the first part of growing a file: zero any data |
@@ -366,7 +261,7 @@ xfs_setattr( | |||
366 | } | 261 | } |
367 | 262 | ||
368 | /* wait for all I/O to complete */ | 263 | /* wait for all I/O to complete */ |
369 | vn_iowait(ip); | 264 | xfs_ioend_wait(ip); |
370 | 265 | ||
371 | if (!code) | 266 | if (!code) |
372 | code = xfs_itruncate_data(ip, iattr->ia_size); | 267 | code = xfs_itruncate_data(ip, iattr->ia_size); |
@@ -388,17 +283,10 @@ xfs_setattr( | |||
388 | } | 283 | } |
389 | commit_flags = XFS_TRANS_RELEASE_LOG_RES; | 284 | commit_flags = XFS_TRANS_RELEASE_LOG_RES; |
390 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 285 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
391 | } | ||
392 | 286 | ||
393 | if (tp) { | ||
394 | xfs_trans_ijoin(tp, ip, lock_flags); | 287 | xfs_trans_ijoin(tp, ip, lock_flags); |
395 | xfs_trans_ihold(tp, ip); | 288 | xfs_trans_ihold(tp, ip); |
396 | } | ||
397 | 289 | ||
398 | /* | ||
399 | * Truncate file. Must have write permission and not be a directory. | ||
400 | */ | ||
401 | if (mask & ATTR_SIZE) { | ||
402 | /* | 290 | /* |
403 | * Only change the c/mtime if we are changing the size | 291 | * Only change the c/mtime if we are changing the size |
404 | * or we are explicitly asked to change it. This handles | 292 | * or we are explicitly asked to change it. This handles |
@@ -438,28 +326,13 @@ xfs_setattr( | |||
438 | */ | 326 | */ |
439 | xfs_iflags_set(ip, XFS_ITRUNCATED); | 327 | xfs_iflags_set(ip, XFS_ITRUNCATED); |
440 | } | 328 | } |
441 | } | 329 | } else if (tp) { |
442 | 330 | xfs_trans_ijoin(tp, ip, lock_flags); | |
443 | /* | 331 | xfs_trans_ihold(tp, ip); |
444 | * Change file access modes. | ||
445 | */ | ||
446 | if (mask & ATTR_MODE) { | ||
447 | ip->i_d.di_mode &= S_IFMT; | ||
448 | ip->i_d.di_mode |= iattr->ia_mode & ~S_IFMT; | ||
449 | |||
450 | inode->i_mode &= S_IFMT; | ||
451 | inode->i_mode |= iattr->ia_mode & ~S_IFMT; | ||
452 | |||
453 | xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); | ||
454 | timeflags |= XFS_ICHGTIME_CHG; | ||
455 | } | 332 | } |
456 | 333 | ||
457 | /* | 334 | /* |
458 | * Change file ownership. Must be the owner or privileged. | 335 | * Change file ownership. Must be the owner or privileged. |
459 | * If the system was configured with the "restricted_chown" | ||
460 | * option, the owner is not permitted to give away the file, | ||
461 | * and can change the group id only to a group of which he | ||
462 | * or she is a member. | ||
463 | */ | 336 | */ |
464 | if (mask & (ATTR_UID|ATTR_GID)) { | 337 | if (mask & (ATTR_UID|ATTR_GID)) { |
465 | /* | 338 | /* |
@@ -503,6 +376,24 @@ xfs_setattr( | |||
503 | timeflags |= XFS_ICHGTIME_CHG; | 376 | timeflags |= XFS_ICHGTIME_CHG; |
504 | } | 377 | } |
505 | 378 | ||
379 | /* | ||
380 | * Change file access modes. | ||
381 | */ | ||
382 | if (mask & ATTR_MODE) { | ||
383 | umode_t mode = iattr->ia_mode; | ||
384 | |||
385 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) | ||
386 | mode &= ~S_ISGID; | ||
387 | |||
388 | ip->i_d.di_mode &= S_IFMT; | ||
389 | ip->i_d.di_mode |= mode & ~S_IFMT; | ||
390 | |||
391 | inode->i_mode &= S_IFMT; | ||
392 | inode->i_mode |= mode & ~S_IFMT; | ||
393 | |||
394 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
395 | timeflags |= XFS_ICHGTIME_CHG; | ||
396 | } | ||
506 | 397 | ||
507 | /* | 398 | /* |
508 | * Change file access or modified times. | 399 | * Change file access or modified times. |
@@ -713,7 +604,7 @@ xfs_fsync( | |||
713 | return XFS_ERROR(EIO); | 604 | return XFS_ERROR(EIO); |
714 | 605 | ||
715 | /* capture size updates in I/O completion before writing the inode. */ | 606 | /* capture size updates in I/O completion before writing the inode. */ |
716 | error = filemap_fdatawait(VFS_I(ip)->i_mapping); | 607 | error = xfs_wait_on_pages(ip, 0, -1); |
717 | if (error) | 608 | if (error) |
718 | return XFS_ERROR(error); | 609 | return XFS_ERROR(error); |
719 | 610 | ||
@@ -1029,6 +920,12 @@ xfs_inactive_symlink_rmt( | |||
1029 | goto error0; | 920 | goto error0; |
1030 | } | 921 | } |
1031 | /* | 922 | /* |
923 | * transaction commit worked ok so we can drop the extra ticket | ||
924 | * reference that we gained in xfs_trans_dup() | ||
925 | */ | ||
926 | xfs_log_ticket_put(tp->t_ticket); | ||
927 | |||
928 | /* | ||
1032 | * Remove the memory for extent descriptions (just bookkeeping). | 929 | * Remove the memory for extent descriptions (just bookkeeping). |
1033 | */ | 930 | */ |
1034 | if (ip->i_df.if_bytes) | 931 | if (ip->i_df.if_bytes) |
@@ -1625,8 +1522,6 @@ xfs_create( | |||
1625 | xfs_trans_set_sync(tp); | 1522 | xfs_trans_set_sync(tp); |
1626 | } | 1523 | } |
1627 | 1524 | ||
1628 | dp->i_gen++; | ||
1629 | |||
1630 | /* | 1525 | /* |
1631 | * Attach the dquot(s) to the inodes and modify them incore. | 1526 | * Attach the dquot(s) to the inodes and modify them incore. |
1632 | * These ids of the inode couldn't have changed since the new | 1527 | * These ids of the inode couldn't have changed since the new |
@@ -1993,13 +1888,6 @@ xfs_remove( | |||
1993 | } | 1888 | } |
1994 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 1889 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
1995 | 1890 | ||
1996 | /* | ||
1997 | * Bump the in memory generation count on the parent | ||
1998 | * directory so that other can know that it has changed. | ||
1999 | */ | ||
2000 | dp->i_gen++; | ||
2001 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); | ||
2002 | |||
2003 | if (is_dir) { | 1891 | if (is_dir) { |
2004 | /* | 1892 | /* |
2005 | * Drop the link from ip's "..". | 1893 | * Drop the link from ip's "..". |
@@ -2009,7 +1897,7 @@ xfs_remove( | |||
2009 | goto out_bmap_cancel; | 1897 | goto out_bmap_cancel; |
2010 | 1898 | ||
2011 | /* | 1899 | /* |
2012 | * Drop the link from dp to ip. | 1900 | * Drop the "." link from ip to self. |
2013 | */ | 1901 | */ |
2014 | error = xfs_droplink(tp, ip); | 1902 | error = xfs_droplink(tp, ip); |
2015 | if (error) | 1903 | if (error) |
@@ -2017,14 +1905,14 @@ xfs_remove( | |||
2017 | } else { | 1905 | } else { |
2018 | /* | 1906 | /* |
2019 | * When removing a non-directory we need to log the parent | 1907 | * When removing a non-directory we need to log the parent |
2020 | * inode here for the i_gen update. For a directory this is | 1908 | * inode here. For a directory this is done implicitly |
2021 | * done implicitly by the xfs_droplink call for the ".." entry. | 1909 | * by the xfs_droplink call for the ".." entry. |
2022 | */ | 1910 | */ |
2023 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); | 1911 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); |
2024 | } | 1912 | } |
2025 | 1913 | ||
2026 | /* | 1914 | /* |
2027 | * Drop the "." link from ip to self. | 1915 | * Drop the link from dp to ip. |
2028 | */ | 1916 | */ |
2029 | error = xfs_droplink(tp, ip); | 1917 | error = xfs_droplink(tp, ip); |
2030 | if (error) | 1918 | if (error) |
@@ -2178,7 +2066,6 @@ xfs_link( | |||
2178 | if (error) | 2066 | if (error) |
2179 | goto abort_return; | 2067 | goto abort_return; |
2180 | xfs_ichgtime(tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 2068 | xfs_ichgtime(tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
2181 | tdp->i_gen++; | ||
2182 | xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE); | 2069 | xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE); |
2183 | 2070 | ||
2184 | error = xfs_bumplink(tp, sip); | 2071 | error = xfs_bumplink(tp, sip); |
@@ -2355,18 +2242,10 @@ xfs_mkdir( | |||
2355 | } | 2242 | } |
2356 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 2243 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
2357 | 2244 | ||
2358 | /* | ||
2359 | * Bump the in memory version number of the parent directory | ||
2360 | * so that other processes accessing it will recognize that | ||
2361 | * the directory has changed. | ||
2362 | */ | ||
2363 | dp->i_gen++; | ||
2364 | |||
2365 | error = xfs_dir_init(tp, cdp, dp); | 2245 | error = xfs_dir_init(tp, cdp, dp); |
2366 | if (error) | 2246 | if (error) |
2367 | goto error2; | 2247 | goto error2; |
2368 | 2248 | ||
2369 | cdp->i_gen = 1; | ||
2370 | error = xfs_bumplink(tp, dp); | 2249 | error = xfs_bumplink(tp, dp); |
2371 | if (error) | 2250 | if (error) |
2372 | goto error2; | 2251 | goto error2; |
@@ -2653,13 +2532,6 @@ xfs_symlink( | |||
2653 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); | 2532 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); |
2654 | 2533 | ||
2655 | /* | 2534 | /* |
2656 | * Bump the in memory version number of the parent directory | ||
2657 | * so that other processes accessing it will recognize that | ||
2658 | * the directory has changed. | ||
2659 | */ | ||
2660 | dp->i_gen++; | ||
2661 | |||
2662 | /* | ||
2663 | * If this is a synchronous mount, make sure that the | 2535 | * If this is a synchronous mount, make sure that the |
2664 | * symlink transaction goes to disk before returning to | 2536 | * symlink transaction goes to disk before returning to |
2665 | * the user. | 2537 | * the user. |
@@ -2809,7 +2681,7 @@ xfs_reclaim( | |||
2809 | return 0; | 2681 | return 0; |
2810 | } | 2682 | } |
2811 | 2683 | ||
2812 | vn_iowait(ip); | 2684 | xfs_ioend_wait(ip); |
2813 | 2685 | ||
2814 | ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0); | 2686 | ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0); |
2815 | 2687 | ||
@@ -2833,122 +2705,10 @@ xfs_reclaim( | |||
2833 | if (!ip->i_update_core && (ip->i_itemp == NULL)) { | 2705 | if (!ip->i_update_core && (ip->i_itemp == NULL)) { |
2834 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 2706 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
2835 | xfs_iflock(ip); | 2707 | xfs_iflock(ip); |
2836 | return xfs_finish_reclaim(ip, 1, XFS_IFLUSH_DELWRI_ELSE_SYNC); | 2708 | xfs_iflags_set(ip, XFS_IRECLAIMABLE); |
2837 | } else { | 2709 | return xfs_reclaim_inode(ip, 1, XFS_IFLUSH_DELWRI_ELSE_SYNC); |
2838 | xfs_mount_t *mp = ip->i_mount; | ||
2839 | |||
2840 | /* Protect sync and unpin from us */ | ||
2841 | XFS_MOUNT_ILOCK(mp); | ||
2842 | spin_lock(&ip->i_flags_lock); | ||
2843 | __xfs_iflags_set(ip, XFS_IRECLAIMABLE); | ||
2844 | VFS_I(ip)->i_private = NULL; | ||
2845 | ip->i_vnode = NULL; | ||
2846 | spin_unlock(&ip->i_flags_lock); | ||
2847 | list_add_tail(&ip->i_reclaim, &mp->m_del_inodes); | ||
2848 | XFS_MOUNT_IUNLOCK(mp); | ||
2849 | } | ||
2850 | return 0; | ||
2851 | } | ||
2852 | |||
2853 | int | ||
2854 | xfs_finish_reclaim( | ||
2855 | xfs_inode_t *ip, | ||
2856 | int locked, | ||
2857 | int sync_mode) | ||
2858 | { | ||
2859 | xfs_perag_t *pag = xfs_get_perag(ip->i_mount, ip->i_ino); | ||
2860 | struct inode *vp = VFS_I(ip); | ||
2861 | |||
2862 | if (vp && VN_BAD(vp)) | ||
2863 | goto reclaim; | ||
2864 | |||
2865 | /* The hash lock here protects a thread in xfs_iget_core from | ||
2866 | * racing with us on linking the inode back with a vnode. | ||
2867 | * Once we have the XFS_IRECLAIM flag set it will not touch | ||
2868 | * us. | ||
2869 | */ | ||
2870 | write_lock(&pag->pag_ici_lock); | ||
2871 | spin_lock(&ip->i_flags_lock); | ||
2872 | if (__xfs_iflags_test(ip, XFS_IRECLAIM) || | ||
2873 | (!__xfs_iflags_test(ip, XFS_IRECLAIMABLE) && vp == NULL)) { | ||
2874 | spin_unlock(&ip->i_flags_lock); | ||
2875 | write_unlock(&pag->pag_ici_lock); | ||
2876 | if (locked) { | ||
2877 | xfs_ifunlock(ip); | ||
2878 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
2879 | } | ||
2880 | return 1; | ||
2881 | } | ||
2882 | __xfs_iflags_set(ip, XFS_IRECLAIM); | ||
2883 | spin_unlock(&ip->i_flags_lock); | ||
2884 | write_unlock(&pag->pag_ici_lock); | ||
2885 | xfs_put_perag(ip->i_mount, pag); | ||
2886 | |||
2887 | /* | ||
2888 | * If the inode is still dirty, then flush it out. If the inode | ||
2889 | * is not in the AIL, then it will be OK to flush it delwri as | ||
2890 | * long as xfs_iflush() does not keep any references to the inode. | ||
2891 | * We leave that decision up to xfs_iflush() since it has the | ||
2892 | * knowledge of whether it's OK to simply do a delwri flush of | ||
2893 | * the inode or whether we need to wait until the inode is | ||
2894 | * pulled from the AIL. | ||
2895 | * We get the flush lock regardless, though, just to make sure | ||
2896 | * we don't free it while it is being flushed. | ||
2897 | */ | ||
2898 | if (!locked) { | ||
2899 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
2900 | xfs_iflock(ip); | ||
2901 | } | 2710 | } |
2902 | 2711 | xfs_inode_set_reclaim_tag(ip); | |
2903 | /* | ||
2904 | * In the case of a forced shutdown we rely on xfs_iflush() to | ||
2905 | * wait for the inode to be unpinned before returning an error. | ||
2906 | */ | ||
2907 | if (xfs_iflush(ip, sync_mode) == 0) { | ||
2908 | /* synchronize with xfs_iflush_done */ | ||
2909 | xfs_iflock(ip); | ||
2910 | xfs_ifunlock(ip); | ||
2911 | } | ||
2912 | |||
2913 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
2914 | |||
2915 | reclaim: | ||
2916 | xfs_ireclaim(ip); | ||
2917 | return 0; | ||
2918 | } | ||
2919 | |||
2920 | int | ||
2921 | xfs_finish_reclaim_all(xfs_mount_t *mp, int noblock) | ||
2922 | { | ||
2923 | int purged; | ||
2924 | xfs_inode_t *ip, *n; | ||
2925 | int done = 0; | ||
2926 | |||
2927 | while (!done) { | ||
2928 | purged = 0; | ||
2929 | XFS_MOUNT_ILOCK(mp); | ||
2930 | list_for_each_entry_safe(ip, n, &mp->m_del_inodes, i_reclaim) { | ||
2931 | if (noblock) { | ||
2932 | if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) | ||
2933 | continue; | ||
2934 | if (xfs_ipincount(ip) || | ||
2935 | !xfs_iflock_nowait(ip)) { | ||
2936 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
2937 | continue; | ||
2938 | } | ||
2939 | } | ||
2940 | XFS_MOUNT_IUNLOCK(mp); | ||
2941 | if (xfs_finish_reclaim(ip, noblock, | ||
2942 | XFS_IFLUSH_DELWRI_ELSE_ASYNC)) | ||
2943 | delay(1); | ||
2944 | purged = 1; | ||
2945 | break; | ||
2946 | } | ||
2947 | |||
2948 | done = !purged; | ||
2949 | } | ||
2950 | |||
2951 | XFS_MOUNT_IUNLOCK(mp); | ||
2952 | return 0; | 2712 | return 0; |
2953 | } | 2713 | } |
2954 | 2714 | ||
@@ -3197,6 +2957,8 @@ xfs_zero_remaining_bytes( | |||
3197 | bp = xfs_buf_get_noaddr(mp->m_sb.sb_blocksize, | 2957 | bp = xfs_buf_get_noaddr(mp->m_sb.sb_blocksize, |
3198 | XFS_IS_REALTIME_INODE(ip) ? | 2958 | XFS_IS_REALTIME_INODE(ip) ? |
3199 | mp->m_rtdev_targp : mp->m_ddev_targp); | 2959 | mp->m_rtdev_targp : mp->m_ddev_targp); |
2960 | if (!bp) | ||
2961 | return XFS_ERROR(ENOMEM); | ||
3200 | 2962 | ||
3201 | for (offset = startoff; offset <= endoff; offset = lastoffset + 1) { | 2963 | for (offset = startoff; offset <= endoff; offset = lastoffset + 1) { |
3202 | offset_fsb = XFS_B_TO_FSBT(mp, offset); | 2964 | offset_fsb = XFS_B_TO_FSBT(mp, offset); |
@@ -3312,7 +3074,8 @@ xfs_free_file_space( | |||
3312 | need_iolock = 0; | 3074 | need_iolock = 0; |
3313 | if (need_iolock) { | 3075 | if (need_iolock) { |
3314 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | 3076 | xfs_ilock(ip, XFS_IOLOCK_EXCL); |
3315 | vn_iowait(ip); /* wait for the completion of any pending DIOs */ | 3077 | /* wait for the completion of any pending DIOs */ |
3078 | xfs_ioend_wait(ip); | ||
3316 | } | 3079 | } |
3317 | 3080 | ||
3318 | rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE); | 3081 | rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE); |
@@ -3474,7 +3237,6 @@ xfs_change_file_space( | |||
3474 | int cmd, | 3237 | int cmd, |
3475 | xfs_flock64_t *bf, | 3238 | xfs_flock64_t *bf, |
3476 | xfs_off_t offset, | 3239 | xfs_off_t offset, |
3477 | cred_t *credp, | ||
3478 | int attr_flags) | 3240 | int attr_flags) |
3479 | { | 3241 | { |
3480 | xfs_mount_t *mp = ip->i_mount; | 3242 | xfs_mount_t *mp = ip->i_mount; |
@@ -3562,7 +3324,7 @@ xfs_change_file_space( | |||
3562 | iattr.ia_valid = ATTR_SIZE; | 3324 | iattr.ia_valid = ATTR_SIZE; |
3563 | iattr.ia_size = startoffset; | 3325 | iattr.ia_size = startoffset; |
3564 | 3326 | ||
3565 | error = xfs_setattr(ip, &iattr, attr_flags, credp); | 3327 | error = xfs_setattr(ip, &iattr, attr_flags); |
3566 | 3328 | ||
3567 | if (error) | 3329 | if (error) |
3568 | return error; | 3330 | return error; |