Re: generic_file_write code segment in 2.2.18

From: Andi Kleen (ak@suse.de)
Date: Thu Jan 04 2001 - 02:51:37 EST


On Wed, Jan 03, 2001 at 09:29:48PM -0800, Asang K Dani wrote:
> hi everyone,
> I was trying to understand following piece of code in
> 'generic_file_read' (mm/filemap.c) for 2.2.18 kernel. The code
> segment
> is as follows:
>
> ----------------------------------------------------------------
> dest = (char *) page_address(page) + offset;
> if (dest != buf) { /* See comment in
> update_vm_cache_cond. */
> bytes -= copy_from_user(dest, buf, bytes);
> flush_dcache_page(page_address(page));
> }
> status = -EFAULT;
> if (bytes)
> status = inode->i_op->updatepage(file, page,
> offset, bytes, sync);
>
> unlock:
> /* Mark it unlocked again and drop the page.. */
> clear_bit(PG_locked, &page->flags);
> wake_up(&page->wait);
> page_cache_release(page);
>
> if (status < 0)
> break;
>
> written += status;
> count -= status;
> pos += status;
> buf += status;
> ----------------------------------------------------------------
> copy_from_user returns the number of bytes copied from userspace
> to 'dest'. In case it succeeds, 'bytes' will be set to 0 after the
> call. However, 'status' is set to -EFAULT. So wouldn't it break
> out of the while loop (prematurely)?

The code is buggy as far as I can see. copy_from_user doesn't return the
number of bytes copied, but the number of bytes not copied when an error
occurs (or 0 on success).

Correct would be:

        
--- linux-work/mm/filemap.c-o Wed Jan 3 17:37:27 2001
+++ linux-work/mm/filemap.c Thu Jan 4 08:48:42 2001
@@ -1685,11 +1685,11 @@
                  */
                 dest = (char *) page_address(page) + offset;
                 if (dest != buf) { /* See comment in update_vm_cache_cond. */
- bytes -= copy_from_user(dest, buf, bytes);
+ if (copy_from_user(dest, buf, bytes))
+ status = -EFAULT;
                         flush_dcache_page(page_address(page));
                 }
- status = -EFAULT;
- if (bytes)
+ if (!status)
                         status = inode->i_op->updatepage(file, page, offset, bytes, sync);
 
  unlock:

-Andi

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sun Jan 07 2001 - 21:00:17 EST