core/linux/aufs3-loopback.patch

288 lines
8.1 KiB
Diff

aufs3.6 loopback patch
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 3bba655..bc9351f 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -500,7 +500,7 @@ out:
}
struct switch_request {
- struct file *file;
+ struct file *file, *virt_file;
struct completion wait;
};
@@ -560,7 +560,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);
@@ -568,6 +569,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);
@@ -584,7 +586,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);
}
/*
@@ -603,6 +605,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);
@@ -611,6 +614,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
@@ -624,6 +634,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;
@@ -640,9 +651,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;
@@ -654,17 +672,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 (lo->lo_flags & LO_FLAGS_PARTSCAN)
ioctl_by_bdev(bdev, BLKRRPART, 0);
return 0;
out_putf:
fput(file);
+ if (virt_file)
+ fput(virt_file);
out:
return error;
}
@@ -807,7 +829,7 @@ static void loop_config_discard(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;
@@ -822,6 +844,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)
@@ -870,6 +898,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;
@@ -915,6 +944,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);
@@ -924,6 +954,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);
@@ -970,6 +1002,7 @@ loop_init_xfer(struct loop_device *lo, struct loop_func_table *xfer,
static int loop_clr_fd(struct loop_device *lo)
{
struct file *filp = lo->lo_backing_file;
+ struct file *virt_filp = lo->lo_backing_virt_file;
gfp_t gfp = lo->old_gfp_mask;
struct block_device *bdev = lo->lo_device;
@@ -990,6 +1023,7 @@ static int loop_clr_fd(struct loop_device *lo)
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);
@@ -1030,6 +1064,8 @@ static int loop_clr_fd(struct loop_device *lo)
* 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 896f3e7..40d875e 100644
--- a/fs/aufs/f_op.c
+++ b/fs/aufs/f_op.c
@@ -352,7 +352,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 016276a..6b24e8b 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 ccf9ac7..36c4c02 100644
--- a/fs/aufs/super.c
+++ b/fs/aufs/super.c
@@ -780,7 +780,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 9116d2e..02ef853 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1878,6 +1878,10 @@ struct super_operations {
int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
int (*nr_cached_objects)(struct super_block *);
void (*free_cached_objects)(struct super_block *, int);
+#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 11a41a8..c190b78 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;