aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/xfs_file.c2
-rw-r--r--fs/xfs/xfs_vnodeops.c96
-rw-r--r--fs/xfs/xfs_vnodeops.h1
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 */
89STATIC int 89int
90xfs_iozero( 90xfs_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
2099STATIC int
2100xfs_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
2158out_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);
49int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize, 49int 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
52int xfs_iozero(struct xfs_inode *, loff_t, size_t);
52int xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t); 53int xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t);
53int xfs_free_eofblocks(struct xfs_mount *, struct xfs_inode *, bool); 54int xfs_free_eofblocks(struct xfs_mount *, struct xfs_inode *, bool);
54 55