On Thu, 1 Mar 2007 16:25:16 +1100 Kandan Venkataraman wrote:

Sorry, I missed seeing your reposted patch when I replied to the
earlier patch.

> The patch is for tracking writes made to a loop device made through mmap. 

How did you test this?  (what program(s))

> Two new ioctls have been added.
>  
> The ioctl cmd LOOP_GET_PGWRITES retrieves the page offsets of pages that have 
> been written to.
> The ioctl cmd LOOP_CLR_PGWRITES empties the red-black tree

I don't quite understand:  what software would use these ioctls?

> This functionality would allow us to have a read only version and a write 
> version of memory by doing the following:
> Associate a normal file as backing storage for  the loop device and mmap to 
> the loop device. Call this mmapped address space as area1.
> Mmap to a normal file of identical size. Call this mmapped address space as 
> area2.
>  
> Changes made to area1 can be periodically copied to area2 using the ioctl 
> cmds (retreive dirty page offsets and copy the dirty pages from area1 to 
> area2). This facility would provide a quick way of updating the read only 
> version.
> 
> Please CC your reply to [EMAIL PROTECTED]
>  
> The following patch is against vanilla linux-2.6.19.2
>  
> Signed-off-by: Kandan Venkataraman [EMAIL PROTECTED]
> 
> 
> diff -uprN linux-2.6.19.2/drivers/block/loop.c 
> linux-2.6.19.2-new/drivers/block/loop.c
> --- linux-2.6.19.2/drivers/block/loop.c       2007-01-11 06:10:37.000000000 
> +1100
> +++ linux-2.6.19.2-new/drivers/block/loop.c   2007-02-27 17:23:18.000000000 
> +1100
> @@ -74,12 +74,16 @@
>  #include <linux/highmem.h>
>  #include <linux/gfp.h>
>  #include <linux/kthread.h>
> +#include <linux/mm.h>
>  
>  #include <asm/uaccess.h>
>  
>  static int max_loop = 8;
>  static struct loop_device *loop_dev;
>  static struct gendisk **disks;
> +static kmem_cache_t *pgoff_elem_cache;
> +static char*  cache_name = "loop_pgoff_elem_cache";

Use style/format as 2 lines above:
static char *cache_name = "loop_pgoff_elem_cache";

> +static struct file_operations loop_fops;
>  
>  /*
>   * Transfer functions
> @@ -646,6 +650,73 @@ static void do_loop_switch(struct loop_d
>       complete(&p->wait);
>  }
>  
> +
> +
> +static int loop_get_pgwrites(struct loop_device *lo, struct loop_pgoff_array 
> __user *arg)
> +{
> +     struct file *filp = lo->lo_backing_file;
> +     struct loop_pgoff_array array;
> +     loff_t i = 0;
> +     struct rb_node *rb_node  = rb_first(&lo->pgoff_tree);
> +
> +     if (lo->lo_state != Lo_bound)
> +             return -ENXIO;
> +
> +     if (filp == NULL)
> +             return -EINVAL;
> +
> +     if (!lo->lo_track_pgwrite)
> +       return 0;

Indent above with 2 tabs, please.

> +
> +     if (copy_from_user(&array, arg, sizeof (struct loop_pgoff_array)))
> +             return -EFAULT;
> +
> +     while (i < array.max && rb_node != NULL) {
> +
> +       if (put_user(rb_entry(rb_node, struct pgoff_elem, node)->offset, 
> array.pgoff + i))
> +              return -EFAULT;
> +
> +       ++i;
> +       rb_node = rb_next(rb_node);

Indent with tabs, not spaces.

> +     }
> +     array.num = i;
> +
> +     if (copy_to_user(arg, &array, sizeof(array)))
> +       return -EFAULT;

indentation...

> +
> +     return 0;
> +}
>  
>  /*
>   * loop_change_fd switched the backing store of a loopback device to
> @@ -969,6 +1046,14 @@ loop_set_status(struct loop_device *lo, 
>                       return -EFBIG;
>       }
>  
> +     if (info->lo_track_pgwrite)
> +       lo->lo_track_pgwrite = 1;
> +     else {
> +       if (lo->lo_track_pgwrite)
> +              pgoff_tree_clear(&lo->pgoff_tree);
> +       lo->lo_track_pgwrite = 0;
> +     }

indentation

> +
>       memcpy(lo->lo_file_name, info->lo_file_name, LO_NAME_SIZE);
>       memcpy(lo->lo_crypt_name, info->lo_crypt_name, LO_NAME_SIZE);
>       lo->lo_file_name[LO_NAME_SIZE-1] = 0;
> @@ -1322,10 +1416,68 @@ static long lo_compat_ioctl(struct file 
>  }
>  #endif
>  
> +static int pgoff_tree_insert(struct rb_root *rb_root, unsigned long offset)
> +{
> +     struct rb_node ** p = &rb_root->rb_node;
> +     struct rb_node * parent = NULL;

No space after "**" and "*" above.

> +     struct pgoff_elem *pgoff_elem;
> +
> +     while (*p)
> +     {

Don't put { on separate line, just put it after while:
        while (*p) {

> +             parent = *p;
> +             pgoff_elem = rb_entry(parent, struct pgoff_elem, node);
> +
> +             if (offset < pgoff_elem->offset)
> +                     p = &(*p)->rb_left;
> +             else if (offset > pgoff_elem->offset)
> +                     p = &(*p)->rb_right;
> +             else
> +                     return 0;
> +     }
> +
> +     pgoff_elem = kmem_cache_alloc(pgoff_elem_cache, GFP_KERNEL);
> +     if (!pgoff_elem)
> +       return -ENOMEM;

indentation.

> +     pgoff_elem->offset = offset;
> +
> +     rb_link_node(&pgoff_elem->node, parent, p);
> +     rb_insert_color(&pgoff_elem->node, rb_root);
> +
> +     return 0;
> +}
> +
> +
> +struct vm_operations_struct loop_file_vm_ops = {
> +     .nopage         = filemap_nopage,
> +     .populate       = filemap_populate,
> +     .page_mkwrite = loop_track_pgwrites
> +};
> +
> +static int loop_file_mmap(struct file * file, struct vm_area_struct * vma)
> +{
> +     /* This is used for a general mmap of a disk file */
> +  int err = generic_file_mmap(file, vma);
> +
> +  if (err)
> +      return err;
> +

Odd/inconsistent indentation above/below.  Above lines should be
indented with one tab (2 tabs on 'return').

> +     vma->vm_ops = &loop_file_vm_ops;
> +     return 0;
> +}
> +
> @@ -1401,6 +1553,12 @@ EXPORT_SYMBOL(loop_unregister_transfer);
>  static int __init loop_init(void)
>  {
>       int     i;
> +     struct inode inode;
> +
> +     /* a roundabout way to retrieve def_blk_fops but avoids undefined 
> reference warning */

Should there be a clean kernel API instead of this roundabout way?

> +     init_special_inode(&inode, S_IFBLK, 0);
> +     loop_fops = *(inode.i_fop);
> +     loop_fops.mmap = loop_file_mmap;
>  
>       if (max_loop < 1 || max_loop > 256) {
>               printk(KERN_WARNING "loop: invalid max_loop (must be between"
> @@ -1411,6 +1569,10 @@ static int __init loop_init(void)
>       if (register_blkdev(LOOP_MAJOR, "loop"))
>               return -EIO;
>  
> +     pgoff_elem_cache = kmem_cache_create(cache_name, sizeof(struct 
> pgoff_elem), 0, SLAB_HWCACHE_ALIGN, NULL, NULL);

line too long.

> +     if (!pgoff_elem_cache)
> +       goto out_mem0;

indentation.

> +
>       loop_dev = kmalloc(max_loop * sizeof(struct loop_device), GFP_KERNEL);
>       if (!loop_dev)
>               goto out_mem1;
> diff -uprN linux-2.6.19.2/include/linux/loop.h 
> linux-2.6.19.2-new/include/linux/loop.h
> --- linux-2.6.19.2/include/linux/loop.h       2007-01-11 06:10:37.000000000 
> +1100
> +++ linux-2.6.19.2-new/include/linux/loop.h   2007-02-27 17:23:28.000000000 
> +1100
> @@ -66,6 +69,12 @@ struct loop_device {
>       request_queue_t         *lo_queue;
>  };
>  
> +struct pgoff_elem {
> +

no blank line here.

> +  struct rb_node     node;
> +  unsigned long offset;
> +};
> +
>  #endif /* __KERNEL__ */
>  
>  /*
> @@ -105,12 +114,20 @@ struct loop_info64 {
>       __u32              lo_encrypt_type;
>       __u32              lo_encrypt_key_size;         /* ioctl w/o */
>       __u32              lo_flags;                    /* ioctl r/o */
> +     __u32                   lo_track_pgwrite; 

Make the fields align.  And that line ends with trailing space.
(There are 2 new patch lines like that; please don't do that.)

>       __u8               lo_file_name[LO_NAME_SIZE];
>       __u8               lo_crypt_name[LO_NAME_SIZE];
>       __u8               lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
>       __u64              lo_init[2];
>  };
>  
> +struct loop_pgoff_array {
> +  __u64 max; /* size of array passed by user */
> +  __u64 num; /* number of entries filled in by driver */
> +  __u64 *pgoff; /* array of page offsets of pages written to by mmap */
> +};
> +
> +
>  /*
>   * Loop filter types
>   */
> @@ -157,5 +174,7 @@ int loop_unregister_transfer(int number)
>  #define LOOP_SET_STATUS64    0x4C04
>  #define LOOP_GET_STATUS64    0x4C05
>  #define LOOP_CHANGE_FD               0x4C06
> +#define LOOP_GET_PGWRITES    0x4C07
> +#define LOOP_CLR_PGWRITES    0x4C08
>  
>  #endif
> -

---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to