From patchwork Mon Jul 1 16:49:56 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Shilovsky X-Patchwork-Id: 2808931 Return-Path: X-Original-To: patchwork-cifs-client@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 03BA3BF4A1 for ; Mon, 1 Jul 2013 16:45:01 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 90883201C4 for ; Mon, 1 Jul 2013 16:44:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 569F4201C3 for ; Mon, 1 Jul 2013 16:44:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754625Ab3GAQop (ORCPT ); Mon, 1 Jul 2013 12:44:45 -0400 Received: from mail-la0-f45.google.com ([209.85.215.45]:64770 "EHLO mail-la0-f45.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752123Ab3GAQnE (ORCPT ); Mon, 1 Jul 2013 12:43:04 -0400 Received: by mail-la0-f45.google.com with SMTP id fr10so4611156lab.32 for ; Mon, 01 Jul 2013 09:43:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=E55tX+nFsuVxJ7uhkJCthOTzs9VuV03LC2Z4/sIvxW8=; b=SjkJA0XkYUAtn6EbEg9pk9I3I935RzP3B5jBSKzQ5fWHOgNjKVgwOoq62dtptH0M+Z vJjVLFTuEnzLs+hSoCA9XPVd5e2IHER9rDUHkTRD7ZZ7VT2C6jDwRrXKYOr6xlFdMg0q rbuk5fbE9InhGOlQg2i79NOuH2yFlnqv0u8O3+KIsaMQ5Y6wkrAM/bpeW2cbsYYSNfG8 2SKcu9g36Bh/RL74Tcl9ewR4vwrhcwep2nHRLkUnTCh2KjjOQlpnp1gjF3/RYS76cpc6 TwFbWnFdPKnajQX+AXWjZDJZBuqg3ivbBI7UjuzUo/ddHZaZYbotcB3a8xXFtaXn4a4j 1dVw== X-Received: by 10.112.170.166 with SMTP id an6mr12174742lbc.22.1372696981991; Mon, 01 Jul 2013 09:43:01 -0700 (PDT) Received: from workstation.localdomain (PPPoE-78-29-83-145.san.ru. [78.29.83.145]) by mx.google.com with ESMTPSA id m1sm7595442lag.3.2013.07.01.09.43.00 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 01 Jul 2013 09:43:01 -0700 (PDT) From: Pavel Shilovsky To: linux-kernel@vger.kernel.org Cc: linux-cifs@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-nfs@vger.kernel.org, wine-devel@winehq.org Subject: [PATCH v7 4/7] CIFS: Add O_DENY* open flags support Date: Mon, 1 Jul 2013 20:49:56 +0400 Message-Id: <1372697399-21361-5-git-send-email-piastry@etersoft.ru> X-Mailer: git-send-email 1.8.1.5 In-Reply-To: <1372697399-21361-1-git-send-email-piastry@etersoft.ru> References: <1372697399-21361-1-git-send-email-piastry@etersoft.ru> Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Construct share_access value from O_DENY* flags and send it to the server. Use NTCreateAndX command rather than Trans2 all the time we have any of O_DENY* flags regardless of unix extensions support. Also change smb error mapping of NT_STATUS_SHARING_VIOLATION to -ESHAREDENIED. Signed-off-by: Pavel Shilovsky --- fs/cifs/cifsfs.c | 2 +- fs/cifs/cifsglob.h | 16 +++++++++++++++- fs/cifs/dir.c | 4 ++++ fs/cifs/file.c | 15 +++++++++++++-- fs/cifs/inode.c | 5 +++-- fs/cifs/netmisc.c | 2 +- fs/cifs/smb2maperror.c | 2 +- fs/locks.c | 11 ++++++++++- include/linux/fs.h | 1 + 9 files changed, 49 insertions(+), 9 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 345fc89..92bd685 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -799,7 +799,7 @@ struct file_system_type cifs_fs_type = { .name = "cifs", .mount = cifs_do_mount, .kill_sb = cifs_kill_sb, - /* .fs_flags */ + .fs_flags = FS_DOES_SHARELOCK, }; MODULE_ALIAS_FS("cifs"); const struct inode_operations cifs_dir_inode_ops = { diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 80af61d..85703f6 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -465,7 +465,7 @@ struct smb_vol { CIFS_MOUNT_CIFS_BACKUPUID | CIFS_MOUNT_CIFS_BACKUPGID) #define CIFS_MS_MASK (MS_RDONLY | MS_MANDLOCK | MS_NOEXEC | MS_NOSUID | \ - MS_NODEV | MS_SYNCHRONOUS) + MS_NODEV | MS_SYNCHRONOUS | MS_SHARELOCK) struct cifs_mnt_data { struct cifs_sb_info *cifs_sb; @@ -947,6 +947,20 @@ struct cifsFileInfo { struct work_struct oplock_break; /* work for oplock breaks */ }; +static inline int +cifs_get_share_flags(unsigned int flags) +{ + int share_access = 0; + + if (!(flags & O_DENYREAD)) + share_access |= FILE_SHARE_READ; + if (!(flags & O_DENYWRITE)) + share_access |= FILE_SHARE_WRITE; + if (!(flags & O_DENYDELETE)) + share_access |= FILE_SHARE_DELETE; + return share_access; +} + struct cifs_io_parms { __u16 netfid; #ifdef CONFIG_CIFS_SMB2 diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index e5f6723..c03ad8c 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -216,7 +216,11 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, goto out; } + if (IS_SHARELOCK(inode)) + share_access = cifs_get_share_flags(oflags); + if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open && + (share_access == FILE_SHARE_ALL) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability))) { rc = cifs_posix_open(full_path, &newinode, inode->i_sb, mode, diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 7631b0c..febf807 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -216,6 +216,8 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, *********************************************************************/ disposition = cifs_get_disposition(f_flags); + if (IS_SHARELOCK(inode)) + share_access = cifs_get_share_flags(f_flags); /* BB pass O_SYNC flag through on file attributes .. BB */ @@ -428,6 +430,7 @@ int cifs_open(struct inode *inode, struct file *file) int rc = -EACCES; unsigned int xid; __u32 oplock; + int share_access = FILE_SHARE_ALL; struct cifs_sb_info *cifs_sb; struct TCP_Server_Info *server; struct cifs_tcon *tcon; @@ -463,8 +466,12 @@ int cifs_open(struct inode *inode, struct file *file) else oplock = 0; - if (!tcon->broken_posix_open && tcon->unix_ext && - cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & + if (IS_SHARELOCK(inode)) + share_access = cifs_get_share_flags(file->f_flags); + + if (!tcon->broken_posix_open && tcon->unix_ext && cap_unix(tcon->ses) && + (share_access == FILE_SHARE_ALL) && + (CIFS_UNIX_POSIX_PATH_OPS_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability))) { /* can not refresh inode info since size could be stale */ rc = cifs_posix_open(full_path, &inode, inode->i_sb, @@ -631,7 +638,11 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) else oplock = 0; + if (IS_SHARELOCK(inode)) + share_access = cifs_get_share_flags(cfile->f_flags); + if (tcon->unix_ext && cap_unix(tcon->ses) && + (share_access == FILE_SHARE_ALL) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability))) { /* diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 039d9a1..7aed606 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1167,7 +1167,8 @@ psx_del_no_retry: cifs_drop_nlink(inode); } else if (rc == -ENOENT) { d_drop(dentry); - } else if (rc == -EBUSY) { + } else if (rc == -ESHAREDENIED) { + rc = -EBUSY; if (server->ops->rename_pending_delete) { rc = server->ops->rename_pending_delete(full_path, dentry, xid); @@ -1514,7 +1515,7 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry, * source. Note that cross directory moves do not work with * rename by filehandle to various Windows servers. */ - if (rc == 0 || rc != -EBUSY) + if (rc == 0 || rc != -ESHAREDENIED) goto do_rename_exit; /* open-file renames don't work across directories */ diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index c0b25b2..a9c8bef 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -62,7 +62,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = { {ERRdiffdevice, -EXDEV}, {ERRnofiles, -ENOENT}, {ERRwriteprot, -EROFS}, - {ERRbadshare, -EBUSY}, + {ERRbadshare, -ESHAREDENIED}, {ERRlock, -EACCES}, {ERRunsup, -EINVAL}, {ERRnosuchshare, -ENXIO}, diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c index 494c912..d70b6ca 100644 --- a/fs/cifs/smb2maperror.c +++ b/fs/cifs/smb2maperror.c @@ -356,7 +356,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = { {STATUS_PORT_CONNECTION_REFUSED, -ECONNREFUSED, "STATUS_PORT_CONNECTION_REFUSED"}, {STATUS_INVALID_PORT_HANDLE, -EIO, "STATUS_INVALID_PORT_HANDLE"}, - {STATUS_SHARING_VIOLATION, -EBUSY, "STATUS_SHARING_VIOLATION"}, + {STATUS_SHARING_VIOLATION, -ESHAREDENIED, "STATUS_SHARING_VIOLATION"}, {STATUS_QUOTA_EXCEEDED, -EDQUOT, "STATUS_QUOTA_EXCEEDED"}, {STATUS_INVALID_PAGE_PROTECTION, -EIO, "STATUS_INVALID_PAGE_PROTECTION"}, diff --git a/fs/locks.c b/fs/locks.c index c2fa136..09c1d0e 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -847,6 +847,10 @@ sharelock_may_delete(struct dentry *dentry) if (!IS_SHARELOCK(dentry->d_inode)) return rc; + /* Don't check a lock on file systems that do it internally */ + if (dentry->d_inode->i_sb->s_type->fs_flags & FS_DOES_SHARELOCK) + return rc; + lock_flocks(); for_each_lock(dentry->d_inode, before) { struct file_lock *fl = *before; @@ -875,8 +879,13 @@ sharelock_lock_file(struct file *filp) { struct file_lock *lock; int error = 0; + struct inode *inode = filp->f_path.dentry->d_inode; + + if (!IS_SHARELOCK(inode)) + return error; - if (!IS_SHARELOCK(filp->f_path.dentry->d_inode)) + /* Don't set a lock on file systems that do it internally */ + if (inode->i_sb->s_type->fs_flags & FS_DOES_SHARELOCK) return error; error = flock_make_lock(filp, &lock, deny_flags_to_cmd(filp->f_flags)); diff --git a/include/linux/fs.h b/include/linux/fs.h index 3247fb4..f802776b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1821,6 +1821,7 @@ struct file_system_type { #define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */ #define FS_USERNS_DEV_MOUNT 16 /* A userns mount does not imply MNT_NODEV */ #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */ +#define FS_DOES_SHARELOCK 65536 /* FS does sharelocks internally */ struct dentry *(*mount) (struct file_system_type *, int, const char *, void *); void (*kill_sb) (struct super_block *);