diff options
Diffstat (limited to 'fs/ntfs/file.c')
-rw-r--r-- | fs/ntfs/file.c | 26 |
1 files changed, 14 insertions, 12 deletions
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 88292f9e4b9b..2e42c2dcae12 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c | |||
@@ -1358,7 +1358,7 @@ err_out: | |||
1358 | goto out; | 1358 | goto out; |
1359 | } | 1359 | } |
1360 | 1360 | ||
1361 | static size_t __ntfs_copy_from_user_iovec(char *vaddr, | 1361 | static size_t __ntfs_copy_from_user_iovec_inatomic(char *vaddr, |
1362 | const struct iovec *iov, size_t iov_ofs, size_t bytes) | 1362 | const struct iovec *iov, size_t iov_ofs, size_t bytes) |
1363 | { | 1363 | { |
1364 | size_t total = 0; | 1364 | size_t total = 0; |
@@ -1376,10 +1376,6 @@ static size_t __ntfs_copy_from_user_iovec(char *vaddr, | |||
1376 | bytes -= len; | 1376 | bytes -= len; |
1377 | vaddr += len; | 1377 | vaddr += len; |
1378 | if (unlikely(left)) { | 1378 | if (unlikely(left)) { |
1379 | /* | ||
1380 | * Zero the rest of the target like __copy_from_user(). | ||
1381 | */ | ||
1382 | memset(vaddr, 0, bytes); | ||
1383 | total -= left; | 1379 | total -= left; |
1384 | break; | 1380 | break; |
1385 | } | 1381 | } |
@@ -1420,11 +1416,13 @@ static inline void ntfs_set_next_iovec(const struct iovec **iovp, | |||
1420 | * pages (out to offset + bytes), to emulate ntfs_copy_from_user()'s | 1416 | * pages (out to offset + bytes), to emulate ntfs_copy_from_user()'s |
1421 | * single-segment behaviour. | 1417 | * single-segment behaviour. |
1422 | * | 1418 | * |
1423 | * We call the same helper (__ntfs_copy_from_user_iovec()) both when atomic and | 1419 | * We call the same helper (__ntfs_copy_from_user_iovec_inatomic()) both |
1424 | * when not atomic. This is ok because __ntfs_copy_from_user_iovec() calls | 1420 | * when atomic and when not atomic. This is ok because |
1425 | * __copy_from_user_inatomic() and it is ok to call this when non-atomic. In | 1421 | * __ntfs_copy_from_user_iovec_inatomic() calls __copy_from_user_inatomic() |
1426 | * fact, the only difference between __copy_from_user_inatomic() and | 1422 | * and it is ok to call this when non-atomic. |
1427 | * __copy_from_user() is that the latter calls might_sleep(). And on many | 1423 | * Infact, the only difference between __copy_from_user_inatomic() and |
1424 | * __copy_from_user() is that the latter calls might_sleep() and the former | ||
1425 | * should not zero the tail of the buffer on error. And on many | ||
1428 | * architectures __copy_from_user_inatomic() is just defined to | 1426 | * architectures __copy_from_user_inatomic() is just defined to |
1429 | * __copy_from_user() so it makes no difference at all on those architectures. | 1427 | * __copy_from_user() so it makes no difference at all on those architectures. |
1430 | */ | 1428 | */ |
@@ -1441,14 +1439,18 @@ static inline size_t ntfs_copy_from_user_iovec(struct page **pages, | |||
1441 | if (len > bytes) | 1439 | if (len > bytes) |
1442 | len = bytes; | 1440 | len = bytes; |
1443 | kaddr = kmap_atomic(*pages, KM_USER0); | 1441 | kaddr = kmap_atomic(*pages, KM_USER0); |
1444 | copied = __ntfs_copy_from_user_iovec(kaddr + ofs, | 1442 | copied = __ntfs_copy_from_user_iovec_inatomic(kaddr + ofs, |
1445 | *iov, *iov_ofs, len); | 1443 | *iov, *iov_ofs, len); |
1446 | kunmap_atomic(kaddr, KM_USER0); | 1444 | kunmap_atomic(kaddr, KM_USER0); |
1447 | if (unlikely(copied != len)) { | 1445 | if (unlikely(copied != len)) { |
1448 | /* Do it the slow way. */ | 1446 | /* Do it the slow way. */ |
1449 | kaddr = kmap(*pages); | 1447 | kaddr = kmap(*pages); |
1450 | copied = __ntfs_copy_from_user_iovec(kaddr + ofs, | 1448 | copied = __ntfs_copy_from_user_iovec_inatomic(kaddr + ofs, |
1451 | *iov, *iov_ofs, len); | 1449 | *iov, *iov_ofs, len); |
1450 | /* | ||
1451 | * Zero the rest of the target like __copy_from_user(). | ||
1452 | */ | ||
1453 | memset(kaddr + ofs + copied, 0, len - copied); | ||
1452 | kunmap(*pages); | 1454 | kunmap(*pages); |
1453 | if (unlikely(copied != len)) | 1455 | if (unlikely(copied != len)) |
1454 | goto err_out; | 1456 | goto err_out; |