diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-04-09 12:55:47 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-04-11 22:30:21 -0400 |
commit | 3309dd04cbcd2cdad168485af5cf3576b5051e49 (patch) | |
tree | 3e01f865306dee01b31f34c9e7e819a5f42a4087 /mm | |
parent | 90320251db0fe3d05f2b10686ec936c7d6ecd99a (diff) |
switch generic_write_checks() to iocb and iter
... returning -E... upon error and amount of data left in iter after
(possible) truncation upon success. Note, that normal case gives
a non-zero (positive) return value, so any tests for != 0 _must_ be
updated.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Conflicts:
fs/ext4/file.c
Diffstat (limited to 'mm')
-rw-r--r-- | mm/filemap.c | 44 |
1 files changed, 19 insertions, 25 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index dfc573c6ec25..243997a26e7c 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -2260,36 +2260,38 @@ EXPORT_SYMBOL(read_cache_page_gfp); | |||
2260 | * Returns appropriate error code that caller should return or | 2260 | * Returns appropriate error code that caller should return or |
2261 | * zero in case that write should be allowed. | 2261 | * zero in case that write should be allowed. |
2262 | */ | 2262 | */ |
2263 | inline int generic_write_checks(struct file *file, loff_t *pos, size_t *count) | 2263 | inline ssize_t generic_write_checks(struct kiocb *iocb, struct iov_iter *from) |
2264 | { | 2264 | { |
2265 | struct file *file = iocb->ki_filp; | ||
2265 | struct inode *inode = file->f_mapping->host; | 2266 | struct inode *inode = file->f_mapping->host; |
2266 | unsigned long limit = rlimit(RLIMIT_FSIZE); | 2267 | unsigned long limit = rlimit(RLIMIT_FSIZE); |
2268 | loff_t pos; | ||
2267 | 2269 | ||
2268 | if (unlikely(*pos < 0)) | 2270 | if (!iov_iter_count(from)) |
2269 | return -EINVAL; | 2271 | return 0; |
2270 | 2272 | ||
2271 | /* FIXME: this is for backwards compatibility with 2.4 */ | 2273 | /* FIXME: this is for backwards compatibility with 2.4 */ |
2272 | if (file->f_flags & O_APPEND) | 2274 | if (file->f_flags & O_APPEND) |
2273 | *pos = i_size_read(inode); | 2275 | iocb->ki_pos = i_size_read(inode); |
2276 | |||
2277 | pos = iocb->ki_pos; | ||
2274 | 2278 | ||
2275 | if (limit != RLIM_INFINITY) { | 2279 | if (limit != RLIM_INFINITY) { |
2276 | if (*pos >= limit) { | 2280 | if (iocb->ki_pos >= limit) { |
2277 | send_sig(SIGXFSZ, current, 0); | 2281 | send_sig(SIGXFSZ, current, 0); |
2278 | return -EFBIG; | 2282 | return -EFBIG; |
2279 | } | 2283 | } |
2280 | if (*count > limit - (typeof(limit))*pos) | 2284 | iov_iter_truncate(from, limit - (unsigned long)pos); |
2281 | *count = limit - (typeof(limit))*pos; | ||
2282 | } | 2285 | } |
2283 | 2286 | ||
2284 | /* | 2287 | /* |
2285 | * LFS rule | 2288 | * LFS rule |
2286 | */ | 2289 | */ |
2287 | if (unlikely(*pos + *count > MAX_NON_LFS && | 2290 | if (unlikely(pos + iov_iter_count(from) > MAX_NON_LFS && |
2288 | !(file->f_flags & O_LARGEFILE))) { | 2291 | !(file->f_flags & O_LARGEFILE))) { |
2289 | if (*pos >= MAX_NON_LFS) | 2292 | if (pos >= MAX_NON_LFS) |
2290 | return -EFBIG; | 2293 | return -EFBIG; |
2291 | if (*count > MAX_NON_LFS - (unsigned long)*pos) | 2294 | iov_iter_truncate(from, MAX_NON_LFS - (unsigned long)pos); |
2292 | *count = MAX_NON_LFS - (unsigned long)*pos; | ||
2293 | } | 2295 | } |
2294 | 2296 | ||
2295 | /* | 2297 | /* |
@@ -2299,16 +2301,11 @@ inline int generic_write_checks(struct file *file, loff_t *pos, size_t *count) | |||
2299 | * exceeded without writing data we send a signal and return EFBIG. | 2301 | * exceeded without writing data we send a signal and return EFBIG. |
2300 | * Linus frestrict idea will clean these up nicely.. | 2302 | * Linus frestrict idea will clean these up nicely.. |
2301 | */ | 2303 | */ |
2302 | if (unlikely(*pos >= inode->i_sb->s_maxbytes)) { | 2304 | if (unlikely(pos >= inode->i_sb->s_maxbytes)) |
2303 | if (*count || *pos > inode->i_sb->s_maxbytes) { | 2305 | return -EFBIG; |
2304 | return -EFBIG; | ||
2305 | } | ||
2306 | /* zero-length writes at ->s_maxbytes are OK */ | ||
2307 | } | ||
2308 | 2306 | ||
2309 | if (unlikely(*pos + *count > inode->i_sb->s_maxbytes)) | 2307 | iov_iter_truncate(from, inode->i_sb->s_maxbytes - pos); |
2310 | *count = inode->i_sb->s_maxbytes - *pos; | 2308 | return iov_iter_count(from); |
2311 | return 0; | ||
2312 | } | 2309 | } |
2313 | EXPORT_SYMBOL(generic_write_checks); | 2310 | EXPORT_SYMBOL(generic_write_checks); |
2314 | 2311 | ||
@@ -2618,14 +2615,11 @@ ssize_t generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
2618 | struct file *file = iocb->ki_filp; | 2615 | struct file *file = iocb->ki_filp; |
2619 | struct inode *inode = file->f_mapping->host; | 2616 | struct inode *inode = file->f_mapping->host; |
2620 | ssize_t ret; | 2617 | ssize_t ret; |
2621 | size_t count = iov_iter_count(from); | ||
2622 | 2618 | ||
2623 | mutex_lock(&inode->i_mutex); | 2619 | mutex_lock(&inode->i_mutex); |
2624 | ret = generic_write_checks(file, &iocb->ki_pos, &count); | 2620 | ret = generic_write_checks(iocb, from); |
2625 | if (!ret && count) { | 2621 | if (ret > 0) |
2626 | iov_iter_truncate(from, count); | ||
2627 | ret = __generic_file_write_iter(iocb, from); | 2622 | ret = __generic_file_write_iter(iocb, from); |
2628 | } | ||
2629 | mutex_unlock(&inode->i_mutex); | 2623 | mutex_unlock(&inode->i_mutex); |
2630 | 2624 | ||
2631 | if (ret > 0) { | 2625 | if (ret > 0) { |