public inbox for linux-xfs@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Fix up xfs_buf_associate_memory()
@ 2007-11-23  4:29 Lachlan McIlroy
  2007-11-23 13:43 ` Christoph Hellwig
  0 siblings, 1 reply; 3+ messages in thread
From: Lachlan McIlroy @ 2007-11-23  4:29 UTC (permalink / raw)
  To: xfs-dev, xfs-oss

[-- Attachment #1: Type: text/plain, Size: 654 bytes --]

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

[-- Attachment #2: xfs_buf.diff --]
[-- Type: text/x-patch, Size: 1419 bytes --]

--- fs/xfs/linux-2.6/xfs_buf.c_1.247	2007-11-23 12:03:16.000000000 +1100
+++ fs/xfs/linux-2.6/xfs_buf.c	2007-11-23 12:02:32.000000000 +1100
@@ -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;

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Fix up xfs_buf_associate_memory()
  2007-11-23  4:29 [PATCH] Fix up xfs_buf_associate_memory() Lachlan McIlroy
@ 2007-11-23 13:43 ` Christoph Hellwig
  2007-11-26  0:25   ` Lachlan McIlroy
  0 siblings, 1 reply; 3+ messages in thread
From: Christoph Hellwig @ 2007-11-23 13:43 UTC (permalink / raw)
  To: Lachlan McIlroy; +Cc: xfs-dev, xfs-oss

On Fri, Nov 23, 2007 at 03:29:06PM +1100, Lachlan McIlroy wrote:
> 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.

Last time I tried to clean up this gem everything went bezerk, so be
aware :)


--- fs/xfs/linux-2.6/xfs_buf.c_1.247	2007-11-23 12:03:16.000000000 +1100
+++ fs/xfs/linux-2.6/xfs_buf.c	2007-11-23 12:02:32.000000000 +1100
@@ -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;
	}

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Fix up xfs_buf_associate_memory()
  2007-11-23 13:43 ` Christoph Hellwig
@ 2007-11-26  0:25   ` Lachlan McIlroy
  0 siblings, 0 replies; 3+ messages in thread
From: Lachlan McIlroy @ 2007-11-26  0:25 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: xfs-dev, xfs-oss

Christoph Hellwig wrote:
> On Fri, Nov 23, 2007 at 03:29:06PM +1100, Lachlan McIlroy wrote:
>> 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.
> 
> Last time I tried to clean up this gem everything went bezerk, so be
> aware :)
> 
> 
> --- fs/xfs/linux-2.6/xfs_buf.c_1.247	2007-11-23 12:03:16.000000000 +1100
> +++ fs/xfs/linux-2.6/xfs_buf.c	2007-11-23 12:02:32.000000000 +1100
> @@ -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 :)

I just left those as they were before the change.  I'll tidy them too.

> 
> +	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;
> 	}
> 

Fine with me.

Thanks.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2007-11-26  0:26 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-11-23  4:29 [PATCH] Fix up xfs_buf_associate_memory() Lachlan McIlroy
2007-11-23 13:43 ` Christoph Hellwig
2007-11-26  0:25   ` Lachlan McIlroy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox