From patchwork Tue Apr 20 20:07:12 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 50562 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.samba.org (fn.samba.org [216.83.154.106]) by ozlabs.org (Postfix) with ESMTP id 71DACB7D0E for ; Wed, 21 Apr 2010 06:07:33 +1000 (EST) Received: from fn.samba.org (localhost [127.0.0.1]) by lists.samba.org (Postfix) with ESMTP id C26F3465C2; Tue, 20 Apr 2010 14:07:33 -0600 (MDT) X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on fn.samba.org X-Spam-Level: X-Spam-Status: No, score=-3.4 required=3.8 tests=AWL, BAYES_00, NO_MORE_FUNN, SPF_PASS autolearn=no version=3.2.5 X-Original-To: linux-cifs-client@lists.samba.org Delivered-To: linux-cifs-client@lists.samba.org Received: from cdptpa-omtalb.mail.rr.com (cdptpa-omtalb.mail.rr.com [75.180.132.121]) by lists.samba.org (Postfix) with ESMTP id 02F78AD24C for ; Tue, 20 Apr 2010 14:07:22 -0600 (MDT) X-Authority-Analysis: v=1.1 cv=ozfpW0B87ixv+y7a1W07/YoomWMeieABhgxoD9XXnPM= c=1 sm=0 a=NUMYgiBnAxkA:10 a=ld/erqUjW76FpBUqCqkKeA==:17 a=20KFwNOVAAAA:8 a=_DYKSEo_ZaC3wi3pGhoA:9 a=g70pmkL9B7uqF47BK_YA:7 a=sue6NjevMaXo1SK56yypB6wHXP8A:4 a=jEp0ucaQiEUA:10 a=ld/erqUjW76FpBUqCqkKeA==:117 X-Cloudmark-Score: 0 X-Originating-IP: 71.70.153.3 Received: from [71.70.153.3] ([71.70.153.3:45265] helo=mail.poochiereds.net) by cdptpa-oedge01.mail.rr.com (envelope-from ) (ecelerity 2.2.2.39 r()) with ESMTP id 98/AA-25246-8790ECB4; Tue, 20 Apr 2010 20:07:21 +0000 Received: by mail.poochiereds.net (Postfix, from userid 4447) id 3AEA858094; Tue, 20 Apr 2010 16:07:20 -0400 (EDT) From: Jeff Layton To: linux-cifs-client@lists.samba.org, linux-fsdevel@vger.kernel.org Date: Tue, 20 Apr 2010 16:07:12 -0400 Message-Id: <1271794039-22787-5-git-send-email-jlayton@redhat.com> X-Mailer: git-send-email 1.6.6.1 In-Reply-To: <1271794039-22787-1-git-send-email-jlayton@redhat.com> References: <1271794039-22787-1-git-send-email-jlayton@redhat.com> Cc: smfrench@gmail.com Subject: [linux-cifs-client] [PATCH 04/11] cifs: have find_readable/writable_file filter by fsuid X-BeenThere: linux-cifs-client@lists.samba.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: The Linux CIFS VFS client List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-cifs-client-bounces@lists.samba.org Errors-To: linux-cifs-client-bounces@lists.samba.org When we implement multisession mounts, we'll need to filter filehandles by fsuid. Add a flag for multisession mounts and code to filter by fsuid when it's set. Signed-off-by: Jeff Layton --- fs/cifs/cifs_fs_sb.h | 3 ++- fs/cifs/cifsacl.c | 4 ++-- fs/cifs/cifsproto.h | 4 ++-- fs/cifs/dir.c | 1 + fs/cifs/file.c | 31 ++++++++++++++++++++++++------- fs/cifs/inode.c | 6 +++--- 6 files changed, 34 insertions(+), 15 deletions(-) diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 4797787..e658723 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -33,6 +33,7 @@ #define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */ #define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */ #define CIFS_MOUNT_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/ +#define CIFS_MOUNT_MULTISES 0x8000 /* multisession mount */ struct cifs_sb_info { struct cifsTconInfo *tcon; /* primary mount */ @@ -44,7 +45,7 @@ struct cifs_sb_info { gid_t mnt_gid; mode_t mnt_file_mode; mode_t mnt_dir_mode; - int mnt_cifs_flags; + unsigned int mnt_cifs_flags; int prepathlen; char *prepath; /* relative path under the share to mount to */ #ifdef CONFIG_CIFS_DFS_UPCALL diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index b8dd664..c2fb35c 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -603,7 +603,7 @@ static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, struct cifsFileInfo *open_file = NULL; if (inode) - open_file = find_readable_file(CIFS_I(inode)); + open_file = find_readable_file(CIFS_I(inode), true); if (!open_file) return get_cifs_acl_by_path(cifs_sb, path, pacllen); @@ -661,7 +661,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, cFYI(DBG2, ("set ACL for %s from mode 0x%x", path, inode->i_mode)); - open_file = find_readable_file(CIFS_I(inode)); + open_file = find_readable_file(CIFS_I(inode), true); if (!open_file) return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 55f3282..ca341fc 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -66,9 +66,9 @@ extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length); extern bool is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); -extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); +extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool); #ifdef CONFIG_CIFS_EXPERIMENTAL -extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *); +extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool); #endif extern unsigned int smbCalcSize(struct smb_hdr *ptr); extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index b482486..e563314 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -148,6 +148,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, pCifsFile->netfid = fileHandle; pCifsFile->pid = current->tgid; + pCifsFile->uid = current_fsuid(); pCifsFile->pInode = igrab(newinode); pCifsFile->mnt = mnt; pCifsFile->pfile = file; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index ba8a61f..651dde4 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1185,9 +1185,15 @@ static ssize_t cifs_write(struct file *file, const char *write_data, } #ifdef CONFIG_CIFS_EXPERIMENTAL -struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode) +struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, + bool fsuid_only) { struct cifsFileInfo *open_file = NULL; + struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); + + /* only filter by fsuid on multisession mounts */ + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTISES)) + fsuid_only = false; read_lock(&GlobalSMBSeslock); /* we could simply get the first_list_entry since write-only entries @@ -1196,6 +1202,8 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode) list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { if (open_file->closePend) continue; + if (fsuid_only && open_file->uid != current_fsuid()) + continue; if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_RDONLY))) { if (!open_file->invalidHandle) { @@ -1215,9 +1223,11 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode) } #endif -struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) +struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, + bool fsuid_only) { struct cifsFileInfo *open_file; + struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); bool any_available = false; int rc; @@ -1231,13 +1241,19 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) return NULL; } + /* only filter by fsuid on multisession mounts */ + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTISES)) + fsuid_only = false; + read_lock(&GlobalSMBSeslock); refind_writable: list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { - if (open_file->closePend || - (!any_available && open_file->pid != current->tgid)) + if (open_file->closePend) + continue; + if (!any_available && open_file->pid != current->tgid) + continue; + if (fsuid_only && open_file->uid != current_fsuid()) continue; - if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_WRONLY))) { @@ -1332,7 +1348,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) if (mapping->host->i_size - offset < (loff_t)to) to = (unsigned)(mapping->host->i_size - offset); - open_file = find_writable_file(CIFS_I(mapping->host)); + open_file = find_writable_file(CIFS_I(mapping->host), false); if (open_file) { bytes_written = cifs_write(open_file->pfile, write_data, to-from, &offset); @@ -1512,7 +1528,8 @@ retry: * CIFSSMBWrite2. We can't rely on the last handle * we used to still be valid */ - open_file = find_writable_file(CIFS_I(mapping->host)); + open_file = find_writable_file(CIFS_I(mapping->host), + false); if (!open_file) { cERROR(1, ("No writable handles for inode")); rc = -EBADF; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 0aa40d2..e21feaa 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -854,7 +854,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, /* * If the file is already open for write, just use that fileid */ - open_file = find_writable_file(cifsInode); + open_file = find_writable_file(cifsInode, true); if (open_file) { netfid = open_file->netfid; netpid = open_file->pid; @@ -1670,7 +1670,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, * writebehind data than the SMB timeout for the SetPathInfo * request would allow */ - open_file = find_writable_file(cifsInode); + open_file = find_writable_file(cifsInode, true); if (open_file) { __u16 nfid = open_file->netfid; __u32 npid = open_file->pid; @@ -1830,7 +1830,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) args->ctime = NO_CHANGE_64; args->device = 0; - open_file = find_writable_file(cifsInode); + open_file = find_writable_file(cifsInode, true); if (open_file) { u16 nfid = open_file->netfid; u32 npid = open_file->pid;