ceph: avoid 32-bit page index overflow
PATCH 1/1 ceph: avoid 32-bit page index overflow
A pgoff_t is defined (by default) to have type (unsigned long). On architectures such as i686 that's a 32-bit type. The ceph address space code was attempting to produce 64 bit offsets by shifting a page's index by PAGE_CACHE_SHIFT, but the result was not what was desired because the shift occurred before the result got promoted to 64 bits.
Fix this by casting all uses of page->index used in this way to the desired 64-bit type.
This fixes http://tracker.newdream.net/issues/3112
--- fs/ceph/addr.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
fs/ceph/addr.c +0 -0
@@ -205,7 +205,7 @@ static int readpage_nounlock(struct file *filp,
struct page *page)
dout("readpage inode %p file %p page %p index %lu\n",
inode, filp, page, page->index);
err = ceph_osdc_readpages(osdc, ceph_vino(inode), &ci->i_layout,
- page->index << PAGE_CACHE_SHIFT, &len,
+ (u64) page->index << PAGE_CACHE_SHIFT, &len,
ci->i_truncate_seq, ci->i_truncate_size, &page, 1, 0);
if (err == -ENOENT)
@@ -286,7 +286,7 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max)
int nr_pages = 0;
int ret;
- off = page->index << PAGE_CACHE_SHIFT;
+ off = (u64) page->index << PAGE_CACHE_SHIFT;
/* count pages */
next_index = page->index;
@@ -426,7 +426,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
struct ceph_inode_info *ci;
struct ceph_fs_client *fsc;
struct ceph_osd_client *osdc;
- loff_t page_off = page->index << PAGE_CACHE_SHIFT;
+ loff_t page_off = (loff_t) page->index << PAGE_CACHE_SHIFT;
int len = PAGE_CACHE_SIZE;
loff_t i_size;
int err = 0;
@@ -817,8 +817,7 @@ get_more_pages:
/* ok */
if (locked_pages == 0) {
/* prepare async write request */
- offset = (unsigned long long)page->index
- << PAGE_CACHE_SHIFT;
+ offset = (u64) page->index << PAGE_CACHE_SHIFT;
len = wsize;
req = ceph_osdc_new_request(&fsc->client->osdc,
&ci->i_layout,
@@ -1180,7 +1179,7 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
struct inode *inode = vma->vm_file->f_dentry->d_inode; struct page *page = vmf->page;
struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
- loff_t off = page->index << PAGE_CACHE_SHIFT;
+ loff_t off = (loff_t) page->index << PAGE_CACHE_SHIFT;
loff_t size, len;
int ret;
Signature · 1 line
1.7.9.5
Yay!
Quoted 81 lines · Alex Elder
A
pgoff_tis defined (by default) to have type (unsigned long). On architectures such as i686 that's a 32-bit type. The ceph address space code was attempting to produce 64 bit offsets by shifting a page's index byPAGE_CACHE_SHIFT, but the result was not what was desired because the shift occurred before the result got promoted to 64 bits.Fix this by casting all uses of
page->indexused in this way to the desired 64-bit type.This fixes http://tracker.newdream.net/issues/3112
Reported-by Mohamed Pakkeer <[email protected]>Signed-off-by Alex Elder <[email protected]>--- fs/ceph/addr.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)fs/ceph/addr.c +1
-1@@ -205,7 +205,7 @@ static int readpage_nounlock(struct file *filp, struct page *page) dout("readpage inode %p file %p page %p index %lu\n", inode, filp, page, page->index); err =ceph_osdc_readpages (osdc,ceph_vino (inode), &ci->i_layout, - page->index <<PAGE_CACHE_SHIFT , &len, + (u64 ) page->index <<PAGE_CACHE_SHIFT , &len, ci->i_truncate_seq, ci->i_truncate_size, &page,1 ,0 );fs/ceph/addr.c +1
-1if (err == -ENOENT )@@ -286,7 +286,7 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max) int nr_pages = 0;int ret; - off = page->index <<PAGE_CACHE_SHIFT ; + off = (u64 ) page->index <<PAGE_CACHE_SHIFT ;/* count pages */ fs/ceph/addr.c +1
-1next_index = page->index;@@ -426,7 +426,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)struct ceph_inode_info *ci;struct ceph_fs_client *fsc;struct ceph_osd_client *osdc; -loff_t page_off = page->index <<PAGE_CACHE_SHIFT ; +loff_t page_off = (loff_t ) page->index <<PAGE_CACHE_SHIFT ;int len =PAGE_CACHE_SIZE ;loff_t i_size;fs/ceph/addr.c +2
-3int err =0 ;@@ -817,8 +817,7 @@ get_more_pages:/* ok */ if (locked_pages ==0 ) {/* prepare async write request */ - offset = (unsigned long long )page->index - <<PAGE_CACHE_SHIFT ; + offset = (u64 ) page->index <<PAGE_CACHE_SHIFT ; len = wsize; req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout,@@ -1180,7 +1179,7 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)struct inode *inode = vma->vm_file->f_dentry->d_inode;struct page *page = vmf->page;struct ceph_mds_client *mdsc =ceph_inode_to_client (inode)->mdsc; -loff_t off = page->index <<PAGE_CACHE_SHIFT ; +loff_t off = (loff_t ) page->index <<PAGE_CACHE_SHIFT ;loff_t size, len;int ret;Signature · 7 lines
-- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 9 lines · Alex Elder
A
pgoff_tis defined (by default) to have type (unsigned long). On architectures such as i686 that's a 32-bit type. The ceph address space code was attempting to produce 64 bit offsets by shifting a page's index byPAGE_CACHE_SHIFT, but the result was not what was desired because the shift occurred before the result got promoted to 64 bits.Fix this by casting all uses of
page->indexused in this way to the desired 64-bit type.
It would be cleaner if you'd use the page_offset helper, which was added to fix this problem without having to remember the right casts everywhere.
Quoted 8 lines · Christoph Hellwig
Quoted 7 lines · Alex Elder
A
pgoff_tis defined (by default) to have type (unsigned long). On architectures such as i686 that's a 32-bit type. The ceph address space code was attempting to produce 64 bit offsets by shifting a page's index byPAGE_CACHE_SHIFT, but the result was not what was desired because the shift occurred before the result got promoted to 64 bits.
Quoted 6 lines
Quoted 2 lines
Fix this by casting all uses of
page->indexused in this way to the desired 64-bit type.It would be cleaner if you'd use the
page_offsethelper, which was added to fix this problem without having to remember the right casts everywhere.
Will do. Thanks Christoph.
-Alex