diff options
author | Chengguang Xu <cgxu519@gmx.com> | 2018-07-19 10:15:26 -0400 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2018-08-02 15:33:28 -0400 |
commit | 8687a3e2c7a026c173ac2e0d65d869c98c154a3a (patch) | |
tree | 22a099b8e861972165e9e736c335c2ed42bfb817 /fs/ceph/file.c | |
parent | 0671e9968dfb3f99a366df816c361b8e871dba1b (diff) |
ceph: add additional offset check in ceph_write_iter()
If the offset is larger or equal to both real file size and
max file size, then return -EFBIG.
Signed-off-by: Chengguang Xu <cgxu519@gmx.com>
Reviewed-by: "Yan, Zheng" <zyan@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'fs/ceph/file.c')
-rw-r--r-- | fs/ceph/file.c | 15 |
1 files changed, 11 insertions, 4 deletions
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 2c54d2674db6..b9cd9d271dcb 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c | |||
@@ -1384,12 +1384,12 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
1384 | struct ceph_file_info *fi = file->private_data; | 1384 | struct ceph_file_info *fi = file->private_data; |
1385 | struct inode *inode = file_inode(file); | 1385 | struct inode *inode = file_inode(file); |
1386 | struct ceph_inode_info *ci = ceph_inode(inode); | 1386 | struct ceph_inode_info *ci = ceph_inode(inode); |
1387 | struct ceph_osd_client *osdc = | 1387 | struct ceph_fs_client *fsc = ceph_inode_to_client(inode); |
1388 | &ceph_sb_to_client(inode->i_sb)->client->osdc; | ||
1389 | struct ceph_cap_flush *prealloc_cf; | 1388 | struct ceph_cap_flush *prealloc_cf; |
1390 | ssize_t count, written = 0; | 1389 | ssize_t count, written = 0; |
1391 | int err, want, got; | 1390 | int err, want, got; |
1392 | loff_t pos; | 1391 | loff_t pos; |
1392 | loff_t limit = max(i_size_read(inode), fsc->max_file_size); | ||
1393 | 1393 | ||
1394 | if (ceph_snap(inode) != CEPH_NOSNAP) | 1394 | if (ceph_snap(inode) != CEPH_NOSNAP) |
1395 | return -EROFS; | 1395 | return -EROFS; |
@@ -1415,6 +1415,13 @@ retry_snap: | |||
1415 | goto out; | 1415 | goto out; |
1416 | 1416 | ||
1417 | pos = iocb->ki_pos; | 1417 | pos = iocb->ki_pos; |
1418 | if (unlikely(pos >= limit)) { | ||
1419 | err = -EFBIG; | ||
1420 | goto out; | ||
1421 | } else { | ||
1422 | iov_iter_truncate(from, limit - pos); | ||
1423 | } | ||
1424 | |||
1418 | count = iov_iter_count(from); | 1425 | count = iov_iter_count(from); |
1419 | if (ceph_quota_is_max_bytes_exceeded(inode, pos + count)) { | 1426 | if (ceph_quota_is_max_bytes_exceeded(inode, pos + count)) { |
1420 | err = -EDQUOT; | 1427 | err = -EDQUOT; |
@@ -1436,7 +1443,7 @@ retry_snap: | |||
1436 | } | 1443 | } |
1437 | 1444 | ||
1438 | /* FIXME: not complete since it doesn't account for being at quota */ | 1445 | /* FIXME: not complete since it doesn't account for being at quota */ |
1439 | if (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL)) { | 1446 | if (ceph_osdmap_flag(&fsc->client->osdc, CEPH_OSDMAP_FULL)) { |
1440 | err = -ENOSPC; | 1447 | err = -ENOSPC; |
1441 | goto out; | 1448 | goto out; |
1442 | } | 1449 | } |
@@ -1526,7 +1533,7 @@ retry_snap: | |||
1526 | } | 1533 | } |
1527 | 1534 | ||
1528 | if (written >= 0) { | 1535 | if (written >= 0) { |
1529 | if (ceph_osdmap_flag(osdc, CEPH_OSDMAP_NEARFULL)) | 1536 | if (ceph_osdmap_flag(&fsc->client->osdc, CEPH_OSDMAP_NEARFULL)) |
1530 | iocb->ki_flags |= IOCB_DSYNC; | 1537 | iocb->ki_flags |= IOCB_DSYNC; |
1531 | written = generic_write_sync(iocb, written); | 1538 | written = generic_write_sync(iocb, written); |
1532 | } | 1539 | } |