aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_vnodeops.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2012-11-14 01:42:47 -0500
committerBen Myers <bpm@sgi.com>2012-11-14 16:11:19 -0500
commitf5b8911b67eb4f15d95d5e5324d376d4a49d56e8 (patch)
tree35c98fdcbefd3c8a52d062f73775cde9aaac75d6 /fs/xfs/xfs_vnodeops.c
parentde497688daaabbab425a8a969528272ec1d962a6 (diff)
xfs: remove xfs_tosspages
It's a buggy, unnecessary wrapper that is duplicating truncate_pagecache_range(). When replacing the call in xfs_change_file_space(), also ensure that the length being allocated/freed is always positive before making any changes. These checks are done in the lower extent manipulation functions, too, but we need to do them before any page cache operations. Reported-by: Andrew Dahl <adahl@sgi.com> Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-By: Andrew Dahl <adahl@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_vnodeops.c')
-rw-r--r--fs/xfs/xfs_vnodeops.c30
1 files changed, 25 insertions, 5 deletions
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index c2ddd7a43942..de3702a57e55 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -2118,7 +2118,7 @@ xfs_change_file_space(
2118 xfs_fsize_t fsize; 2118 xfs_fsize_t fsize;
2119 int setprealloc; 2119 int setprealloc;
2120 xfs_off_t startoffset; 2120 xfs_off_t startoffset;
2121 xfs_off_t llen; 2121 xfs_off_t end;
2122 xfs_trans_t *tp; 2122 xfs_trans_t *tp;
2123 struct iattr iattr; 2123 struct iattr iattr;
2124 int prealloc_type; 2124 int prealloc_type;
@@ -2139,12 +2139,30 @@ xfs_change_file_space(
2139 return XFS_ERROR(EINVAL); 2139 return XFS_ERROR(EINVAL);
2140 } 2140 }
2141 2141
2142 llen = bf->l_len > 0 ? bf->l_len - 1 : bf->l_len; 2142 /*
2143 * length of <= 0 for resv/unresv/zero is invalid. length for
2144 * alloc/free is ignored completely and we have no idea what userspace
2145 * might have set it to, so set it to zero to allow range
2146 * checks to pass.
2147 */
2148 switch (cmd) {
2149 case XFS_IOC_ZERO_RANGE:
2150 case XFS_IOC_RESVSP:
2151 case XFS_IOC_RESVSP64:
2152 case XFS_IOC_UNRESVSP:
2153 case XFS_IOC_UNRESVSP64:
2154 if (bf->l_len <= 0)
2155 return XFS_ERROR(EINVAL);
2156 break;
2157 default:
2158 bf->l_len = 0;
2159 break;
2160 }
2143 2161
2144 if (bf->l_start < 0 || 2162 if (bf->l_start < 0 ||
2145 bf->l_start > mp->m_super->s_maxbytes || 2163 bf->l_start > mp->m_super->s_maxbytes ||
2146 bf->l_start + llen < 0 || 2164 bf->l_start + bf->l_len < 0 ||
2147 bf->l_start + llen > mp->m_super->s_maxbytes) 2165 bf->l_start + bf->l_len >= mp->m_super->s_maxbytes)
2148 return XFS_ERROR(EINVAL); 2166 return XFS_ERROR(EINVAL);
2149 2167
2150 bf->l_whence = 0; 2168 bf->l_whence = 0;
@@ -2169,7 +2187,9 @@ xfs_change_file_space(
2169 switch (cmd) { 2187 switch (cmd) {
2170 case XFS_IOC_ZERO_RANGE: 2188 case XFS_IOC_ZERO_RANGE:
2171 prealloc_type |= XFS_BMAPI_CONVERT; 2189 prealloc_type |= XFS_BMAPI_CONVERT;
2172 xfs_tosspages(ip, startoffset, startoffset + bf->l_len, 0); 2190 end = round_down(startoffset + bf->l_len, PAGE_SIZE) - 1;
2191 if (startoffset > end)
2192 truncate_pagecache_range(VFS_I(ip), startoffset, end);
2173 /* FALLTHRU */ 2193 /* FALLTHRU */
2174 case XFS_IOC_RESVSP: 2194 case XFS_IOC_RESVSP:
2175 case XFS_IOC_RESVSP64: 2195 case XFS_IOC_RESVSP64: