diff options
Diffstat (limited to 'fs/xfs/xfs_vnodeops.c')
-rw-r--r-- | fs/xfs/xfs_vnodeops.c | 168 |
1 files changed, 121 insertions, 47 deletions
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 2a5c637344b4..d95f565a390e 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include "xfs_filestream.h" | 47 | #include "xfs_filestream.h" |
48 | #include "xfs_vnodeops.h" | 48 | #include "xfs_vnodeops.h" |
49 | #include "xfs_trace.h" | 49 | #include "xfs_trace.h" |
50 | #include "xfs_icache.h" | ||
50 | 51 | ||
51 | /* | 52 | /* |
52 | * The maximum pathlen is 1024 bytes. Since the minimum file system | 53 | * The maximum pathlen is 1024 bytes. Since the minimum file system |
@@ -79,7 +80,7 @@ xfs_readlink_bmap( | |||
79 | d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); | 80 | d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); |
80 | byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); | 81 | byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); |
81 | 82 | ||
82 | bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0); | 83 | bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0, NULL); |
83 | if (!bp) | 84 | if (!bp) |
84 | return XFS_ERROR(ENOMEM); | 85 | return XFS_ERROR(ENOMEM); |
85 | error = bp->b_error; | 86 | error = bp->b_error; |
@@ -150,7 +151,7 @@ xfs_readlink( | |||
150 | * when the link count isn't zero and by xfs_dm_punch_hole() when | 151 | * when the link count isn't zero and by xfs_dm_punch_hole() when |
151 | * punching a hole to EOF. | 152 | * punching a hole to EOF. |
152 | */ | 153 | */ |
153 | STATIC int | 154 | int |
154 | xfs_free_eofblocks( | 155 | xfs_free_eofblocks( |
155 | xfs_mount_t *mp, | 156 | xfs_mount_t *mp, |
156 | xfs_inode_t *ip, | 157 | xfs_inode_t *ip, |
@@ -199,7 +200,7 @@ xfs_free_eofblocks( | |||
199 | if (need_iolock) { | 200 | if (need_iolock) { |
200 | if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) { | 201 | if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) { |
201 | xfs_trans_cancel(tp, 0); | 202 | xfs_trans_cancel(tp, 0); |
202 | return 0; | 203 | return EAGAIN; |
203 | } | 204 | } |
204 | } | 205 | } |
205 | 206 | ||
@@ -237,6 +238,8 @@ xfs_free_eofblocks( | |||
237 | } else { | 238 | } else { |
238 | error = xfs_trans_commit(tp, | 239 | error = xfs_trans_commit(tp, |
239 | XFS_TRANS_RELEASE_LOG_RES); | 240 | XFS_TRANS_RELEASE_LOG_RES); |
241 | if (!error) | ||
242 | xfs_inode_clear_eofblocks_tag(ip); | ||
240 | } | 243 | } |
241 | 244 | ||
242 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 245 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
@@ -425,19 +428,18 @@ xfs_release( | |||
425 | truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED); | 428 | truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED); |
426 | if (truncated) { | 429 | if (truncated) { |
427 | xfs_iflags_clear(ip, XFS_IDIRTY_RELEASE); | 430 | xfs_iflags_clear(ip, XFS_IDIRTY_RELEASE); |
428 | if (VN_DIRTY(VFS_I(ip)) && ip->i_delayed_blks > 0) | 431 | if (VN_DIRTY(VFS_I(ip)) && ip->i_delayed_blks > 0) { |
429 | xfs_flush_pages(ip, 0, -1, XBF_ASYNC, FI_NONE); | 432 | error = -filemap_flush(VFS_I(ip)->i_mapping); |
433 | if (error) | ||
434 | return error; | ||
435 | } | ||
430 | } | 436 | } |
431 | } | 437 | } |
432 | 438 | ||
433 | if (ip->i_d.di_nlink == 0) | 439 | if (ip->i_d.di_nlink == 0) |
434 | return 0; | 440 | return 0; |
435 | 441 | ||
436 | if ((S_ISREG(ip->i_d.di_mode) && | 442 | if (xfs_can_free_eofblocks(ip, false)) { |
437 | (VFS_I(ip)->i_size > 0 || | ||
438 | (VN_CACHED(VFS_I(ip)) > 0 || ip->i_delayed_blks > 0)) && | ||
439 | (ip->i_df.if_flags & XFS_IFEXTENTS)) && | ||
440 | (!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) { | ||
441 | 443 | ||
442 | /* | 444 | /* |
443 | * If we can't get the iolock just skip truncating the blocks | 445 | * If we can't get the iolock just skip truncating the blocks |
@@ -464,7 +466,7 @@ xfs_release( | |||
464 | return 0; | 466 | return 0; |
465 | 467 | ||
466 | error = xfs_free_eofblocks(mp, ip, true); | 468 | error = xfs_free_eofblocks(mp, ip, true); |
467 | if (error) | 469 | if (error && error != EAGAIN) |
468 | return error; | 470 | return error; |
469 | 471 | ||
470 | /* delalloc blocks after truncation means it really is dirty */ | 472 | /* delalloc blocks after truncation means it really is dirty */ |
@@ -513,13 +515,12 @@ xfs_inactive( | |||
513 | goto out; | 515 | goto out; |
514 | 516 | ||
515 | if (ip->i_d.di_nlink != 0) { | 517 | if (ip->i_d.di_nlink != 0) { |
516 | if ((S_ISREG(ip->i_d.di_mode) && | 518 | /* |
517 | (VFS_I(ip)->i_size > 0 || | 519 | * force is true because we are evicting an inode from the |
518 | (VN_CACHED(VFS_I(ip)) > 0 || ip->i_delayed_blks > 0)) && | 520 | * cache. Post-eof blocks must be freed, lest we end up with |
519 | (ip->i_df.if_flags & XFS_IFEXTENTS) && | 521 | * broken free space accounting. |
520 | (!(ip->i_d.di_flags & | 522 | */ |
521 | (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) || | 523 | if (xfs_can_free_eofblocks(ip, true)) { |
522 | ip->i_delayed_blks != 0))) { | ||
523 | error = xfs_free_eofblocks(mp, ip, false); | 524 | error = xfs_free_eofblocks(mp, ip, false); |
524 | if (error) | 525 | if (error) |
525 | return VN_INACTIVE_CACHE; | 526 | return VN_INACTIVE_CACHE; |
@@ -777,7 +778,7 @@ xfs_create( | |||
777 | XFS_TRANS_PERM_LOG_RES, log_count); | 778 | XFS_TRANS_PERM_LOG_RES, log_count); |
778 | if (error == ENOSPC) { | 779 | if (error == ENOSPC) { |
779 | /* flush outstanding delalloc blocks and retry */ | 780 | /* flush outstanding delalloc blocks and retry */ |
780 | xfs_flush_inodes(dp); | 781 | xfs_flush_inodes(mp); |
781 | error = xfs_trans_reserve(tp, resblks, log_res, 0, | 782 | error = xfs_trans_reserve(tp, resblks, log_res, 0, |
782 | XFS_TRANS_PERM_LOG_RES, log_count); | 783 | XFS_TRANS_PERM_LOG_RES, log_count); |
783 | } | 784 | } |
@@ -1957,12 +1958,11 @@ xfs_free_file_space( | |||
1957 | 1958 | ||
1958 | rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE); | 1959 | rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE); |
1959 | ioffset = offset & ~(rounding - 1); | 1960 | ioffset = offset & ~(rounding - 1); |
1960 | 1961 | error = -filemap_write_and_wait_range(VFS_I(ip)->i_mapping, | |
1961 | if (VN_CACHED(VFS_I(ip)) != 0) { | 1962 | ioffset, -1); |
1962 | error = xfs_flushinval_pages(ip, ioffset, -1, FI_REMAPF_LOCKED); | 1963 | if (error) |
1963 | if (error) | 1964 | goto out_unlock_iolock; |
1964 | goto out_unlock_iolock; | 1965 | truncate_pagecache_range(VFS_I(ip), ioffset, -1); |
1965 | } | ||
1966 | 1966 | ||
1967 | /* | 1967 | /* |
1968 | * Need to zero the stuff we're not freeing, on disk. | 1968 | * Need to zero the stuff we're not freeing, on disk. |
@@ -2095,6 +2095,73 @@ xfs_free_file_space( | |||
2095 | return error; | 2095 | return error; |
2096 | } | 2096 | } |
2097 | 2097 | ||
2098 | |||
2099 | STATIC int | ||
2100 | xfs_zero_file_space( | ||
2101 | struct xfs_inode *ip, | ||
2102 | xfs_off_t offset, | ||
2103 | xfs_off_t len, | ||
2104 | int attr_flags) | ||
2105 | { | ||
2106 | struct xfs_mount *mp = ip->i_mount; | ||
2107 | uint granularity; | ||
2108 | xfs_off_t start_boundary; | ||
2109 | xfs_off_t end_boundary; | ||
2110 | int error; | ||
2111 | |||
2112 | granularity = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE); | ||
2113 | |||
2114 | /* | ||
2115 | * Round the range of extents we are going to convert inwards. If the | ||
2116 | * offset is aligned, then it doesn't get changed so we zero from the | ||
2117 | * start of the block offset points to. | ||
2118 | */ | ||
2119 | start_boundary = round_up(offset, granularity); | ||
2120 | end_boundary = round_down(offset + len, granularity); | ||
2121 | |||
2122 | ASSERT(start_boundary >= offset); | ||
2123 | ASSERT(end_boundary <= offset + len); | ||
2124 | |||
2125 | if (!(attr_flags & XFS_ATTR_NOLOCK)) | ||
2126 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | ||
2127 | |||
2128 | if (start_boundary < end_boundary - 1) { | ||
2129 | /* punch out the page cache over the conversion range */ | ||
2130 | truncate_pagecache_range(VFS_I(ip), start_boundary, | ||
2131 | end_boundary - 1); | ||
2132 | /* convert the blocks */ | ||
2133 | error = xfs_alloc_file_space(ip, start_boundary, | ||
2134 | end_boundary - start_boundary - 1, | ||
2135 | XFS_BMAPI_PREALLOC | XFS_BMAPI_CONVERT, | ||
2136 | attr_flags); | ||
2137 | if (error) | ||
2138 | goto out_unlock; | ||
2139 | |||
2140 | /* We've handled the interior of the range, now for the edges */ | ||
2141 | if (start_boundary != offset) | ||
2142 | error = xfs_iozero(ip, offset, start_boundary - offset); | ||
2143 | if (error) | ||
2144 | goto out_unlock; | ||
2145 | |||
2146 | if (end_boundary != offset + len) | ||
2147 | error = xfs_iozero(ip, end_boundary, | ||
2148 | offset + len - end_boundary); | ||
2149 | |||
2150 | } else { | ||
2151 | /* | ||
2152 | * It's either a sub-granularity range or the range spanned lies | ||
2153 | * partially across two adjacent blocks. | ||
2154 | */ | ||
2155 | error = xfs_iozero(ip, offset, len); | ||
2156 | } | ||
2157 | |||
2158 | out_unlock: | ||
2159 | if (!(attr_flags & XFS_ATTR_NOLOCK)) | ||
2160 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | ||
2161 | return error; | ||
2162 | |||
2163 | } | ||
2164 | |||
2098 | /* | 2165 | /* |
2099 | * xfs_change_file_space() | 2166 | * xfs_change_file_space() |
2100 | * This routine allocates or frees disk space for the given file. | 2167 | * This routine allocates or frees disk space for the given file. |
@@ -2120,10 +2187,8 @@ xfs_change_file_space( | |||
2120 | xfs_fsize_t fsize; | 2187 | xfs_fsize_t fsize; |
2121 | int setprealloc; | 2188 | int setprealloc; |
2122 | xfs_off_t startoffset; | 2189 | xfs_off_t startoffset; |
2123 | xfs_off_t llen; | ||
2124 | xfs_trans_t *tp; | 2190 | xfs_trans_t *tp; |
2125 | struct iattr iattr; | 2191 | struct iattr iattr; |
2126 | int prealloc_type; | ||
2127 | 2192 | ||
2128 | if (!S_ISREG(ip->i_d.di_mode)) | 2193 | if (!S_ISREG(ip->i_d.di_mode)) |
2129 | return XFS_ERROR(EINVAL); | 2194 | return XFS_ERROR(EINVAL); |
@@ -2141,12 +2206,30 @@ xfs_change_file_space( | |||
2141 | return XFS_ERROR(EINVAL); | 2206 | return XFS_ERROR(EINVAL); |
2142 | } | 2207 | } |
2143 | 2208 | ||
2144 | llen = bf->l_len > 0 ? bf->l_len - 1 : bf->l_len; | 2209 | /* |
2210 | * length of <= 0 for resv/unresv/zero is invalid. length for | ||
2211 | * alloc/free is ignored completely and we have no idea what userspace | ||
2212 | * might have set it to, so set it to zero to allow range | ||
2213 | * checks to pass. | ||
2214 | */ | ||
2215 | switch (cmd) { | ||
2216 | case XFS_IOC_ZERO_RANGE: | ||
2217 | case XFS_IOC_RESVSP: | ||
2218 | case XFS_IOC_RESVSP64: | ||
2219 | case XFS_IOC_UNRESVSP: | ||
2220 | case XFS_IOC_UNRESVSP64: | ||
2221 | if (bf->l_len <= 0) | ||
2222 | return XFS_ERROR(EINVAL); | ||
2223 | break; | ||
2224 | default: | ||
2225 | bf->l_len = 0; | ||
2226 | break; | ||
2227 | } | ||
2145 | 2228 | ||
2146 | if (bf->l_start < 0 || | 2229 | if (bf->l_start < 0 || |
2147 | bf->l_start > mp->m_super->s_maxbytes || | 2230 | bf->l_start > mp->m_super->s_maxbytes || |
2148 | bf->l_start + llen < 0 || | 2231 | bf->l_start + bf->l_len < 0 || |
2149 | bf->l_start + llen > mp->m_super->s_maxbytes) | 2232 | bf->l_start + bf->l_len >= mp->m_super->s_maxbytes) |
2150 | return XFS_ERROR(EINVAL); | 2233 | return XFS_ERROR(EINVAL); |
2151 | 2234 | ||
2152 | bf->l_whence = 0; | 2235 | bf->l_whence = 0; |
@@ -2154,29 +2237,20 @@ xfs_change_file_space( | |||
2154 | startoffset = bf->l_start; | 2237 | startoffset = bf->l_start; |
2155 | fsize = XFS_ISIZE(ip); | 2238 | fsize = XFS_ISIZE(ip); |
2156 | 2239 | ||
2157 | /* | ||
2158 | * XFS_IOC_RESVSP and XFS_IOC_UNRESVSP will reserve or unreserve | ||
2159 | * file space. | ||
2160 | * These calls do NOT zero the data space allocated to the file, | ||
2161 | * nor do they change the file size. | ||
2162 | * | ||
2163 | * XFS_IOC_ALLOCSP and XFS_IOC_FREESP will allocate and free file | ||
2164 | * space. | ||
2165 | * These calls cause the new file data to be zeroed and the file | ||
2166 | * size to be changed. | ||
2167 | */ | ||
2168 | setprealloc = clrprealloc = 0; | 2240 | setprealloc = clrprealloc = 0; |
2169 | prealloc_type = XFS_BMAPI_PREALLOC; | ||
2170 | |||
2171 | switch (cmd) { | 2241 | switch (cmd) { |
2172 | case XFS_IOC_ZERO_RANGE: | 2242 | case XFS_IOC_ZERO_RANGE: |
2173 | prealloc_type |= XFS_BMAPI_CONVERT; | 2243 | error = xfs_zero_file_space(ip, startoffset, bf->l_len, |
2174 | xfs_tosspages(ip, startoffset, startoffset + bf->l_len, 0); | 2244 | attr_flags); |
2175 | /* FALLTHRU */ | 2245 | if (error) |
2246 | return error; | ||
2247 | setprealloc = 1; | ||
2248 | break; | ||
2249 | |||
2176 | case XFS_IOC_RESVSP: | 2250 | case XFS_IOC_RESVSP: |
2177 | case XFS_IOC_RESVSP64: | 2251 | case XFS_IOC_RESVSP64: |
2178 | error = xfs_alloc_file_space(ip, startoffset, bf->l_len, | 2252 | error = xfs_alloc_file_space(ip, startoffset, bf->l_len, |
2179 | prealloc_type, attr_flags); | 2253 | XFS_BMAPI_PREALLOC, attr_flags); |
2180 | if (error) | 2254 | if (error) |
2181 | return error; | 2255 | return error; |
2182 | setprealloc = 1; | 2256 | setprealloc = 1; |