diff options
-rw-r--r-- | fs/xfs/xfs_file.c | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_vnodeops.c | 96 | ||||
-rw-r--r-- | fs/xfs/xfs_vnodeops.h | 1 |
3 files changed, 77 insertions, 22 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 400b187595bb..67284edb84d7 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -86,7 +86,7 @@ xfs_rw_ilock_demote( | |||
86 | * valid before the operation, it will be read from disk before | 86 | * valid before the operation, it will be read from disk before |
87 | * being partially zeroed. | 87 | * being partially zeroed. |
88 | */ | 88 | */ |
89 | STATIC int | 89 | int |
90 | xfs_iozero( | 90 | xfs_iozero( |
91 | struct xfs_inode *ip, /* inode */ | 91 | struct xfs_inode *ip, /* inode */ |
92 | loff_t pos, /* offset in file */ | 92 | loff_t pos, /* offset in file */ |
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 26880793feca..d95f565a390e 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
@@ -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 end; | ||
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); |
@@ -2172,31 +2237,20 @@ xfs_change_file_space( | |||
2172 | startoffset = bf->l_start; | 2237 | startoffset = bf->l_start; |
2173 | fsize = XFS_ISIZE(ip); | 2238 | fsize = XFS_ISIZE(ip); |
2174 | 2239 | ||
2175 | /* | ||
2176 | * XFS_IOC_RESVSP and XFS_IOC_UNRESVSP will reserve or unreserve | ||
2177 | * file space. | ||
2178 | * These calls do NOT zero the data space allocated to the file, | ||
2179 | * nor do they change the file size. | ||
2180 | * | ||
2181 | * XFS_IOC_ALLOCSP and XFS_IOC_FREESP will allocate and free file | ||
2182 | * space. | ||
2183 | * These calls cause the new file data to be zeroed and the file | ||
2184 | * size to be changed. | ||
2185 | */ | ||
2186 | setprealloc = clrprealloc = 0; | 2240 | setprealloc = clrprealloc = 0; |
2187 | prealloc_type = XFS_BMAPI_PREALLOC; | ||
2188 | |||
2189 | switch (cmd) { | 2241 | switch (cmd) { |
2190 | case XFS_IOC_ZERO_RANGE: | 2242 | case XFS_IOC_ZERO_RANGE: |
2191 | prealloc_type |= XFS_BMAPI_CONVERT; | 2243 | error = xfs_zero_file_space(ip, startoffset, bf->l_len, |
2192 | end = round_down(startoffset + bf->l_len, PAGE_SIZE) - 1; | 2244 | attr_flags); |
2193 | if (startoffset <= end) | 2245 | if (error) |
2194 | truncate_pagecache_range(VFS_I(ip), startoffset, end); | 2246 | return error; |
2195 | /* FALLTHRU */ | 2247 | setprealloc = 1; |
2248 | break; | ||
2249 | |||
2196 | case XFS_IOC_RESVSP: | 2250 | case XFS_IOC_RESVSP: |
2197 | case XFS_IOC_RESVSP64: | 2251 | case XFS_IOC_RESVSP64: |
2198 | error = xfs_alloc_file_space(ip, startoffset, bf->l_len, | 2252 | error = xfs_alloc_file_space(ip, startoffset, bf->l_len, |
2199 | prealloc_type, attr_flags); | 2253 | XFS_BMAPI_PREALLOC, attr_flags); |
2200 | if (error) | 2254 | if (error) |
2201 | return error; | 2255 | return error; |
2202 | setprealloc = 1; | 2256 | setprealloc = 1; |
diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h index 91a03fa3814f..5163022d9808 100644 --- a/fs/xfs/xfs_vnodeops.h +++ b/fs/xfs/xfs_vnodeops.h | |||
@@ -49,6 +49,7 @@ int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags); | |||
49 | int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize, | 49 | int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize, |
50 | int flags, struct attrlist_cursor_kern *cursor); | 50 | int flags, struct attrlist_cursor_kern *cursor); |
51 | 51 | ||
52 | int xfs_iozero(struct xfs_inode *, loff_t, size_t); | ||
52 | int xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t); | 53 | int xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t); |
53 | int xfs_free_eofblocks(struct xfs_mount *, struct xfs_inode *, bool); | 54 | int xfs_free_eofblocks(struct xfs_mount *, struct xfs_inode *, bool); |
54 | 55 | ||