Fix up xfs_buf_associate_memory()
PATCH 1/1 Fix up xfs_buf_associate_memory()
Fixed a few bugs in xfs_buf_associate_memory() including:
- calculation of 'page_count' was incorrect as it did not consider the offset of 'mem' into the first page. The logic to bump 'page_count' didn't work if 'len' was <= PAGE_CACHE_SIZE (ie offset = 3k, len = 2k).
- setting b_buffer_length to 'len' is incorrect if 'offset' is > 0. Set it to the total length of the buffer.
- I suspect that passing a non-aligned address into mem_to_page() for the first page may have been causing issues - don't know but just tidy up that code anyway.
These fixes prevent an data corruption issue that can occur during log replay.
Lachlan
xfs/linux-2.6/xfs_buf.c renamed from xfs/linux-2.6/xfs_buf.c_1.247 +10 -17
@@ -726,14 +726,14 @@ xfs_buf_associate_memory(int rval;int i =0 ;size_t ptr; -size_t end, end_cur; +size_t buflen;off_t offset;int page_count; - page_count =PAGE_CACHE_ALIGN (len) >>PAGE_CACHE_SHIFT ; - offset = (off_t ) mem - ((off_t )mem &PAGE_CACHE_MASK ); -if (offset && (len >PAGE_CACHE_SIZE )) - page_count++; + ptr = (size_t ) mem &PAGE_CACHE_MASK ; + offset = (off_t ) mem - (off_t ) ptr; + buflen =PAGE_CACHE_ALIGN (len + offset); + page_count = buflen >>PAGE_CACHE_SHIFT ;/* Free any previous set of page pointers */ if (bp->b_pages)
@@ -747,22 +747,15 @@ xfs_buf_associate_memory(return rval; bp->b_offset = offset; - ptr = (size_t ) mem &PAGE_CACHE_MASK ; - end =PAGE_CACHE_ALIGN ((size_t ) mem + len); - end_cur = end; -/* set up first page */ - bp->b_pages[0 ] =mem_to_page (mem); - - ptr +=PAGE_CACHE_SIZE ; - bp->b_page_count = ++i; -while (ptr < end) { - bp->b_pages[i] =mem_to_page ((void *)ptr); - bp->b_page_count = ++i; + +while (i < bp->b_page_count) { + bp->b_pages[i++] =mem_to_page ((void *)ptr); ptr +=PAGE_CACHE_SIZE ; } bp->b_locked =0 ; - bp->b_count_desired = bp->b_buffer_length = len; + bp->b_count_desired = len; + bp->b_buffer_length = buflen; bp->b_flags |=XBF_MAPPED ;return 0 ;
Quoted 13 lines · Lachlan McIlroy
Fixed a few bugs in
xfs_buf_associate_memory()including:- calculation of '
page_count' was incorrect as it did not consider the offset of 'mem' into the first page. The logic to bump 'page_count' didn't work if 'len' was <=PAGE_CACHE_SIZE(ie offset = 3k, len = 2k).
- settingb_buffer_lengthto 'len' is incorrect if 'offset' is > 0. Set it to the total length of the buffer.
- I suspect that passing a non-aligned address intomem_to_page()for the first page may have been causing issues - don't know but just tidy up that code anyway.
Quoted 2 lines
These fixes prevent an data corruption issue that can occur during log replay.
Last time I tried to clean up this gem everything went bezerk, so be aware :)
xfs/linux-2.6/xfs_buf.c renamed from xfs/linux-2.6/xfs_buf.c_1.247 +3 -0
@@ -726,14 +726,14 @@ xfs_buf_associate_memory(int rval;int i =0 ;size_t ptr; +size_t buflen;off_t offset;int page_count; + ptr = (size_t ) mem &PAGE_CACHE_MASK ; + offset = (off_t ) mem - (off_t ) ptr;
Casting pointers to size_t or off_t makes little sense, these should be unsigned long. And using a variable name of ptr is quite odd :)
+ while (i < bp->b_page_count) {
+ bp->b_pages[i++] = mem_to_page((void *)ptr);
ptr += PAGE_CACHE_SIZE;
}
This could be much cleaner written as:
for (i = 0; i < bp->b_page_count; i++) {
bp->b_pages[i] = mem_to_page((void *)ptr);
ptr += PAGE_CACHE_SIZE;
}Quoted 34 lines · Christoph Hellwig
Quoted 13 lines · Lachlan McIlroy
Fixed a few bugs in
xfs_buf_associate_memory()including:- calculation of '
page_count' was incorrect as it did not consider the offset of 'mem' into the first page. The logic to bump 'page_count' didn't work if 'len' was <=PAGE_CACHE_SIZE(ie offset = 3k, len = 2k).
- settingb_buffer_lengthto 'len' is incorrect if 'offset' is > 0. Set it to the total length of the buffer.
- I suspect that passing a non-aligned address intomem_to_page()for the first page may have been causing issues - don't know but just tidy up that code anyway.Quoted 2 lines
These fixes prevent an data corruption issue that can occur during log replay.
Last time I tried to clean up this gem everything went bezerk, so be aware :)
xfs/linux-2.6/xfs_buf.c renamed from xfs/linux-2.6/xfs_buf.c_1.247 +3
-0@@ -726,14 +726,14 @@ xfs_buf_associate_memory(int rval;int i =0 ;size_t ptr; +size_t buflen;off_t offset;int page_count; + ptr = (size_t ) mem &PAGE_CACHE_MASK ; + offset = (off_t ) mem - (off_t ) ptr;
Quoted 2 lines
Casting pointers to
size_toroff_tmakes little sense, these should be unsigned long. And using a variable name of ptr is quite odd :)
I just left those as they were before the change. I'll tidy them too.
Quoted 6 lines
xfs/linux-2.6/xfs_buf.c renamed from xfs/linux-2.6/xfs_buf.c_1.247 +2
-0+while (i < bp->b_page_count) { + bp->b_pages[i++] =mem_to_page ((void *)ptr); ptr +=PAGE_CACHE_SIZE ; }
Quoted 7 lines
This could be much cleaner written as:
for (i = 0; i < bp->b_page_count; i++) { bp->b_pages[i] = mem_to_page((void *)ptr); ptr += PAGE_CACHE_SIZE; }
Fine with me.
Thanks.