aufs3.0 loopback patch diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 76c8da7..027b839 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -541,7 +541,7 @@ out: } struct switch_request { - struct file *file; + struct file *file, *virt_file; struct completion wait; }; @@ -601,7 +601,8 @@ static int loop_thread(void *data) * First it needs to flush existing IO, it does this by sending a magic * BIO down the pipe. The completion of this BIO does the actual switch. */ -static int loop_switch(struct loop_device *lo, struct file *file) +static int loop_switch(struct loop_device *lo, struct file *file, + struct file *virt_file) { struct switch_request w; struct bio *bio = bio_alloc(GFP_KERNEL, 0); @@ -609,6 +610,7 @@ static int loop_switch(struct loop_device *lo, struct file *file) return -ENOMEM; init_completion(&w.wait); w.file = file; + w.virt_file = virt_file; bio->bi_private = &w; bio->bi_bdev = NULL; loop_make_request(lo->lo_queue, bio); @@ -625,7 +627,7 @@ static int loop_flush(struct loop_device *lo) if (!lo->lo_thread) return 0; - return loop_switch(lo, NULL); + return loop_switch(lo, NULL, NULL); } /* @@ -644,6 +646,7 @@ static void do_loop_switch(struct loop_device *lo, struct switch_request *p) mapping = file->f_mapping; mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask); lo->lo_backing_file = file; + lo->lo_backing_virt_file = p->virt_file; lo->lo_blocksize = S_ISBLK(mapping->host->i_mode) ? mapping->host->i_bdev->bd_block_size : PAGE_SIZE; lo->old_gfp_mask = mapping_gfp_mask(mapping); @@ -652,6 +655,13 @@ out: complete(&p->wait); } +static struct file *loop_real_file(struct file *file) +{ + struct file *f = NULL; + if (file->f_dentry->d_sb->s_op->real_loop) + f = file->f_dentry->d_sb->s_op->real_loop(file); + return f; +} /* * loop_change_fd switched the backing store of a loopback device to @@ -665,6 +675,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, unsigned int arg) { struct file *file, *old_file; + struct file *f, *virt_file = NULL, *old_virt_file; struct inode *inode; int error; @@ -681,9 +692,16 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, file = fget(arg); if (!file) goto out; + f = loop_real_file(file); + if (f) { + virt_file = file; + file = f; + get_file(file); + } inode = file->f_mapping->host; old_file = lo->lo_backing_file; + old_virt_file = lo->lo_backing_virt_file; error = -EINVAL; @@ -695,17 +713,21 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, goto out_putf; /* and ... switch */ - error = loop_switch(lo, file); + error = loop_switch(lo, file, virt_file); if (error) goto out_putf; fput(old_file); + if (old_virt_file) + fput(old_virt_file); if (max_part > 0) ioctl_by_bdev(bdev, BLKRRPART, 0); return 0; out_putf: fput(file); + if (virt_file) + fput(virt_file); out: return error; } @@ -817,7 +839,7 @@ static void loop_sysfs_exit(struct loop_device *lo) static int loop_set_fd(struct loop_device *lo, fmode_t mode, struct block_device *bdev, unsigned int arg) { - struct file *file, *f; + struct file *file, *f, *virt_file = NULL; struct inode *inode; struct address_space *mapping; unsigned lo_blocksize; @@ -832,6 +854,12 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, file = fget(arg); if (!file) goto out; + f = loop_real_file(file); + if (f) { + virt_file = file; + file = f; + get_file(file); + } error = -EBUSY; if (lo->lo_state != Lo_unbound) @@ -892,6 +920,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, lo->lo_device = bdev; lo->lo_flags = lo_flags; lo->lo_backing_file = file; + lo->lo_backing_virt_file = virt_file; lo->transfer = transfer_none; lo->ioctl = NULL; lo->lo_sizelimit = 0; @@ -935,6 +964,7 @@ out_clr: lo->lo_thread = NULL; lo->lo_device = NULL; lo->lo_backing_file = NULL; + lo->lo_backing_virt_file = NULL; lo->lo_flags = 0; set_capacity(lo->lo_disk, 0); invalidate_bdev(bdev); @@ -944,6 +974,8 @@ out_clr: lo->lo_state = Lo_unbound; out_putf: fput(file); + if (virt_file) + fput(virt_file); out: /* This is safe: open() is still holding a reference. */ module_put(THIS_MODULE); @@ -990,6 +1022,7 @@ loop_init_xfer(struct loop_device *lo, struct loop_func_table *xfer, static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) { struct file *filp = lo->lo_backing_file; + struct file *virt_filp = lo->lo_backing_virt_file; gfp_t gfp = lo->old_gfp_mask; if (lo->lo_state != Lo_bound) @@ -1041,6 +1041,7 @@ static int loop_clr_fd(struct loop_devic spin_lock_irq(&lo->lo_lock); lo->lo_backing_file = NULL; + lo->lo_backing_virt_file = NULL; spin_unlock_irq(&lo->lo_lock); loop_release_xfer(lo); @@ -1045,6 +1079,8 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) * bd_mutex which is usually taken before lo_ctl_mutex. */ fput(filp); + if (virt_filp) + fput(virt_filp); return 0; } diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c index 5cf9963..1a775fd 100644 --- a/fs/aufs/f_op.c +++ b/fs/aufs/f_op.c @@ -355,7 +355,7 @@ static ssize_t aufs_splice_read(struct file *file, loff_t *ppos, err = -EINVAL; h_file = au_hf_top(file); get_file(h_file); - if (au_test_loopback_kthread()) { + if (0 && au_test_loopback_kthread()) { au_warn_loopback(h_file->f_dentry->d_sb); if (file->f_mapping != h_file->f_mapping) { file->f_mapping = h_file->f_mapping; diff --git a/fs/aufs/loop.c b/fs/aufs/loop.c index 317f0e4..45215c2 100644 --- a/fs/aufs/loop.c +++ b/fs/aufs/loop.c @@ -131,3 +131,19 @@ void au_loopback_fin(void) { kfree(au_warn_loopback_array); } + +/* ---------------------------------------------------------------------- */ + +/* support the loopback block device insude aufs */ + +struct file *aufs_real_loop(struct file *file) +{ + struct file *f; + + BUG_ON(!au_test_aufs(file->f_dentry->d_sb)); + fi_read_lock(file); + f = au_hf_top(file); + fi_read_unlock(file); + AuDebugOn(!f); + return f; +} diff --git a/fs/aufs/loop.h b/fs/aufs/loop.h index b7af6a7..7a50e6e 100644 --- a/fs/aufs/loop.h +++ b/fs/aufs/loop.h @@ -36,6 +36,8 @@ void au_warn_loopback(struct super_block *h_sb); int au_loopback_init(void); void au_loopback_fin(void); + +struct file *aufs_real_loop(struct file *file); #else AuStubInt0(au_test_loopback_overlap, struct super_block *sb, struct dentry *h_adding) @@ -44,6 +46,8 @@ AuStubVoid(au_warn_loopback, struct super_block *h_sb) AuStubInt0(au_loopback_init, void) AuStubVoid(au_loopback_fin, void) + +AuStub(struct file *, aufs_real_loop, return NULL, struct file *file) #endif /* BLK_DEV_LOOP */ #endif /* __KERNEL__ */ diff --git a/fs/aufs/super.c b/fs/aufs/super.c index 6df90a8..51baf21 100644 --- a/fs/aufs/super.c +++ b/fs/aufs/super.c @@ -752,7 +752,10 @@ static const struct super_operations aufs_sop = { .show_options = aufs_show_options, .statfs = aufs_statfs, .put_super = aufs_put_super, - .remount_fs = aufs_remount_fs + .remount_fs = aufs_remount_fs, +#ifdef CONFIG_AUFS_BDEV_LOOP + .real_loop = aufs_real_loop +#endif }; /* ---------------------------------------------------------------------- */ diff --git a/include/linux/fs.h b/include/linux/fs.h index b5b9792..dc57779 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1645,6 +1645,10 @@ struct super_operations { ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); #endif int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t); +#if defined(CONFIG_BLK_DEV_LOOP) || defined(CONFIG_BLK_DEV_LOOP_MODULE) + /* and aufs */ + struct file *(*real_loop)(struct file *); +#endif }; /* diff --git a/include/linux/loop.h b/include/linux/loop.h index 66c194e..37dd916 100644 --- a/include/linux/loop.h +++ b/include/linux/loop.h @@ -48,7 +48,7 @@ struct loop_device { int (*ioctl)(struct loop_device *, int cmd, unsigned long arg); - struct file * lo_backing_file; + struct file * lo_backing_file, *lo_backing_virt_file; struct block_device *lo_device; unsigned lo_blocksize; void *key_data;