From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756018Ab0ICNnW (ORCPT ); Fri, 3 Sep 2010 09:43:22 -0400 Received: from fxip-0047f.externet.hu ([88.209.222.127]:58591 "EHLO pomaz-ex.szeredi.hu" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753362Ab0ICNlu (ORCPT ); Fri, 3 Sep 2010 09:41:50 -0400 Message-Id: <20100903134146.278025655@szeredi.hu> References: <20100903134116.039612691@szeredi.hu> User-Agent: quilt/0.46-1 Date: Fri, 03 Sep 2010 15:41:17 +0200 From: Miklos Szeredi To: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: vaurora@redhat.com, neilb@suse.de, viro@zeniv.linux.org.uk Subject: [PATCH 1/6] vfs: implement open "forwarding" Content-Disposition: inline; filename=vfs-open-redirect.patch Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Miklos Szeredi Add a new file operation f_op->open_other(). This acts just like f_op->open() except the return value can be another open struct file pointer. In that case the original file is discarded and the replacement file is used instead. Signed-off-by: Miklos Szeredi --- fs/open.c | 23 +++++++++++++++++------ include/linux/fs.h | 1 + 2 files changed, 18 insertions(+), 6 deletions(-) Index: linux-2.6/fs/open.c =================================================================== --- linux-2.6.orig/fs/open.c 2010-08-19 09:45:50.000000000 +0200 +++ linux-2.6/fs/open.c 2010-08-19 09:46:27.000000000 +0200 @@ -657,6 +657,7 @@ static struct file *__dentry_open(struct const struct cred *cred) { struct inode *inode; + struct file *ret; int error; f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | @@ -664,6 +665,7 @@ static struct file *__dentry_open(struct inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = __get_file_write_access(inode, mnt); + ret = ERR_PTR(error); if (error) goto cleanup_file; if (!special_file(inode->i_mode)) @@ -678,15 +680,24 @@ static struct file *__dentry_open(struct file_sb_list_add(f, inode->i_sb); error = security_dentry_open(f, cred); + ret = ERR_PTR(error); if (error) goto cleanup_all; - if (!open && f->f_op) - open = f->f_op->open; - if (open) { - error = open(inode, f); - if (error) + if (!open && f->f_op && f->f_op->open_other) { + /* NULL means keep f, non-error non-null means replace */ + ret = f->f_op->open_other(f); + if (IS_ERR(ret) || ret != NULL) goto cleanup_all; + } else { + if (!open && f->f_op) + open = f->f_op->open; + if (open) { + error = open(inode, f); + ret = ERR_PTR(error); + if (error) + goto cleanup_all; + } } ima_counts_get(f); @@ -728,7 +739,7 @@ cleanup_file: put_filp(f); dput(dentry); mntput(mnt); - return ERR_PTR(error); + return ret; } /** Index: linux-2.6/include/linux/fs.h =================================================================== --- linux-2.6.orig/include/linux/fs.h 2010-08-19 09:46:15.000000000 +0200 +++ linux-2.6/include/linux/fs.h 2010-08-19 09:46:27.000000000 +0200 @@ -1494,6 +1494,7 @@ struct file_operations { long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); + struct file *(*open_other) (struct file *); int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, int datasync); --