From patchwork Tue Sep 23 02:02:49 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steve French X-Patchwork-Id: 4951761 Return-Path: X-Original-To: patchwork-cifs-client@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id DA60C9F2BB for ; Tue, 23 Sep 2014 02:03:14 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 8AEF220115 for ; Tue, 23 Sep 2014 02:03:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 24F042010E for ; Tue, 23 Sep 2014 02:03:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754106AbaIWCDL (ORCPT ); Mon, 22 Sep 2014 22:03:11 -0400 Received: from mail-qg0-f43.google.com ([209.85.192.43]:51860 "EHLO mail-qg0-f43.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754069AbaIWCDK (ORCPT ); Mon, 22 Sep 2014 22:03:10 -0400 Received: by mail-qg0-f43.google.com with SMTP id f51so3890739qge.30 for ; Mon, 22 Sep 2014 19:03:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:from:date:message-id:subject:to:content-type; bh=W0Ly8ZDaUz9Q1o4tiSSzJg5Lci79E5mMjUFrL4CB2TI=; b=xum5/7quz9us3F8cams3hXRNpLfJSeRQmeCk2NPvT/QwDV5RxK6BXFotVwt/hq4ku5 pXv3Vn6C0bmfk0yzQpjpoO3c9MKRqm/w9S+1jD8oTgC2gU6buEyHsmtTn9NDaTFmvUfG OeQiD2GYUEChOuopU2rNTgQmnzPBl2NuvsFa7w/W8TSYe/FKJlpX+XjrdYiLbVooFMFm W4xgRFuMu2+DptPFsHLocYY2fdi3FwPpCyqnOklLy4C2hGm1blBEgVLlZ0oBhimJep3C K9c1oJZQ8e8VqvHgxtcaOHTNGHeskphloXTCxP3HXx9gTCVmHE/RrlVC3+Fkc5xOho1V L6pA== X-Received: by 10.229.229.135 with SMTP id ji7mr35537340qcb.15.1411437789337; Mon, 22 Sep 2014 19:03:09 -0700 (PDT) MIME-Version: 1.0 Received: by 10.140.32.116 with HTTP; Mon, 22 Sep 2014 19:02:49 -0700 (PDT) From: Steve French Date: Mon, 22 Sep 2014 21:02:49 -0500 Message-ID: Subject: [PATCH] [SMB3] Allow mknod and mkfifo on SMB2/SMB3 mounts To: "linux-cifs@vger.kernel.org" , samba-technical Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org X-Spam-Status: No, score=-7.7 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, T_TVD_MIME_EPI,UNPARSEABLE_RELAY autolearn=ham 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 The "sfu" mount option did not work on SMB2/SMB3 mounts. With these changes when the "sfu" mount option is passed in on an smb2/smb2.1/smb3 mount the client can emulate (and recognize) fifo and device (character and device files). In addition the "sfu" mount option should not conflict with "mfsymlinks" (symlink emulation) as we will never create "sfu" style symlinks, but using "sfu" mount option will allow us to recognize existing symlinks, created with Microsoft "Services for Unix" (SFU and SUA). To enable the "sfu" mount option for SMB2/SMB3 the calling syntax of the generic cifs/smb2/smb3 sync_read and sync_write protocol dependent function needed to be changed (we don't have a file struct in all cases), but this actually ended up simplifying the code a little. Patch attached and also at: http://git.samba.org/?p=sfrench/cifs-2.6.git;a=shortlog;h=refs/heads/for-next From 860768062bbf9d19ab3ada43c3bb444d0480ba79 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 22 Sep 2014 05:13:55 -0500 Subject: [PATCH] [SMB3] Allow mknod and mkfifo on SMB2/SMB3 mounts The "sfu" mount option did not work on SMB2/SMB3 mounts. With these changes when the "sfu" mount option is passed in on an smb2/smb2.1/smb3 mount the client can emulate (and recognize) fifo and device (character and device files). In addition the "sfu" mount option should not conflict with "mfsymlinks" (symlink emulation) as we will never create "sfu" style symlinks, but using "sfu" mount option will allow us to recognize existing symlinks, created with Microsoft "Services for Unix" (SFU and SUA). To enable the "sfu" mount option for SMB2/SMB3 the calling syntax of the generic cifs/smb2/smb3 sync_read and sync_write protocol dependent function needed to be changed (we don't have a file struct in all cases), but this actually ended up simplifying the code a little. Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 4 ++-- fs/cifs/connect.c | 16 +++++++++++++--- fs/cifs/dir.c | 22 ++++++++++++++-------- fs/cifs/file.c | 6 +++--- fs/cifs/inode.c | 15 +++++++++++---- fs/cifs/smb1ops.c | 8 ++++---- fs/cifs/smb2ops.c | 12 ++++++------ fs/cifs/smb2pdu.c | 2 ++ 8 files changed, 55 insertions(+), 30 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 25b8392..dae7e37 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -323,11 +323,11 @@ struct smb_version_operations { int (*async_writev)(struct cifs_writedata *, void (*release)(struct kref *)); /* sync read from the server */ - int (*sync_read)(const unsigned int, struct cifsFileInfo *, + int (*sync_read)(const unsigned int, struct cifs_fid *, struct cifs_io_parms *, unsigned int *, char **, int *); /* sync write to the server */ - int (*sync_write)(const unsigned int, struct cifsFileInfo *, + int (*sync_write)(const unsigned int, struct cifs_fid *, struct cifs_io_parms *, unsigned int *, struct kvec *, unsigned long); /* open dir, start readdir */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 36ca204..eff1429 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3239,10 +3239,20 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, } if (pvolume_info->mfsymlinks) { if (pvolume_info->sfu_emul) { - cifs_dbg(VFS, "mount option mfsymlinks ignored if sfu mount option is used\n"); - } else { - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS; + /* + * Our SFU ("Services for Unix" emulation does not allow + * creating symlinks but does allow reading existing SFU + * symlinks (it does allow both creating and reading SFU + * style mknod and FIFOs though). When "mfsymlinks" and + * "sfu" are both enabled at the same time, it allows + * reading both types of symlinks, but will only create + * them with mfsymlinks format. This allows better + * Apple compatibility (probably better for Samba too) + * while still recognizing old Windows style symlinks. + */ + cifs_dbg(VFS, "mount options mfsymlinks and sfu both enabled\n"); } + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS; } if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm)) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 6cbd9c6..dee8849 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -577,12 +577,13 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, struct cifs_io_parms io_parms; char *full_path = NULL; struct inode *newinode = NULL; - int oplock = 0; + __u32 oplock = 0; struct cifs_fid fid; struct cifs_open_parms oparms; FILE_ALL_INFO *buf = NULL; unsigned int bytes_written; struct win_dev *pdev; + struct kvec iov[2]; if (!old_valid_dev(device_number)) return -EINVAL; @@ -658,7 +659,11 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, oparms.fid = &fid; oparms.reconnect = false; - rc = CIFS_open(xid, &oparms, &oplock, buf); + if (tcon->ses->server->oplocks) + oplock = REQ_OPLOCK; + else + oplock = 0; + rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, buf); if (rc) goto mknod_out; @@ -668,25 +673,26 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, */ pdev = (struct win_dev *)buf; - io_parms.netfid = fid.netfid; io_parms.pid = current->tgid; io_parms.tcon = tcon; io_parms.offset = 0; io_parms.length = sizeof(struct win_dev); + iov[1].iov_base = buf; + iov[1].iov_len = sizeof(struct win_dev); if (S_ISCHR(mode)) { memcpy(pdev->type, "IntxCHR", 8); pdev->major = cpu_to_le64(MAJOR(device_number)); pdev->minor = cpu_to_le64(MINOR(device_number)); - rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev, - NULL, 0); + rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, + &bytes_written, iov, 1); } else if (S_ISBLK(mode)) { memcpy(pdev->type, "IntxBLK", 8); pdev->major = cpu_to_le64(MAJOR(device_number)); pdev->minor = cpu_to_le64(MINOR(device_number)); - rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev, - NULL, 0); + rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, + &bytes_written, iov, 1); } /* else if (S_ISFIFO) */ - CIFSSMBClose(xid, tcon, fid.netfid); + tcon->ses->server->ops->close(xid, tcon, &fid); d_drop(direntry); /* FIXME: add code here to set EAs */ diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 7c018a1..0272fbb 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1687,8 +1687,8 @@ cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data, io_parms.tcon = tcon; io_parms.offset = *offset; io_parms.length = len; - rc = server->ops->sync_write(xid, open_file, &io_parms, - &bytes_written, iov, 1); + rc = server->ops->sync_write(xid, &open_file->fid, + &io_parms, &bytes_written, iov, 1); } if (rc || (bytes_written == 0)) { if (total_written) @@ -3206,7 +3206,7 @@ cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset) io_parms.tcon = tcon; io_parms.offset = *offset; io_parms.length = current_read_size; - rc = server->ops->sync_read(xid, open_file, &io_parms, + rc = server->ops->sync_read(xid, &open_file->fid, &io_parms, &bytes_read, &cur_offset, &buf_type); } while (rc == -EAGAIN); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 7899a40..957fe5e 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -412,7 +412,7 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path, struct cifs_sb_info *cifs_sb, unsigned int xid) { int rc; - int oplock = 0; + __u32 oplock; struct tcon_link *tlink; struct cifs_tcon *tcon; struct cifs_fid fid; @@ -451,8 +451,13 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path, oparms.fid = &fid; oparms.reconnect = false; - rc = CIFS_open(xid, &oparms, &oplock, NULL); + if (tcon->ses->server->oplocks) + oplock = REQ_OPLOCK; + else + oplock = 0; + rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL); if (rc) { + cifs_dbg(FYI, "check sfu type of %s, open rc = %d\n", path, rc); cifs_put_tlink(tlink); return rc; } @@ -464,7 +469,8 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path, io_parms.offset = 0; io_parms.length = 24; - rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type); + rc = tcon->ses->server->ops->sync_read(xid, &fid, &io_parms, + &bytes_read, &pbuf, &buf_type); if ((rc == 0) && (bytes_read >= 8)) { if (memcmp("IntxBLK", pbuf, 8) == 0) { cifs_dbg(FYI, "Block device\n"); @@ -504,7 +510,8 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path, fattr->cf_dtype = DT_REG; rc = -EOPNOTSUPP; /* or some unknown SFU type */ } - CIFSSMBClose(xid, tcon, fid.netfid); + + tcon->ses->server->ops->close(xid, tcon, &fid); cifs_put_tlink(tlink); return rc; } diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 1a6df4b..8601807 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -749,21 +749,21 @@ cifs_flush_file(const unsigned int xid, struct cifs_tcon *tcon, } static int -cifs_sync_read(const unsigned int xid, struct cifsFileInfo *cfile, +cifs_sync_read(const unsigned int xid, struct cifs_fid *pfid, struct cifs_io_parms *parms, unsigned int *bytes_read, char **buf, int *buf_type) { - parms->netfid = cfile->fid.netfid; + parms->netfid = pfid->netfid; return CIFSSMBRead(xid, parms, bytes_read, buf, buf_type); } static int -cifs_sync_write(const unsigned int xid, struct cifsFileInfo *cfile, +cifs_sync_write(const unsigned int xid, struct cifs_fid *pfid, struct cifs_io_parms *parms, unsigned int *written, struct kvec *iov, unsigned long nr_segs) { - parms->netfid = cfile->fid.netfid; + parms->netfid = pfid->netfid; return CIFSSMBWrite2(xid, parms, written, iov, nr_segs); } diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 489f48b..af44686 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -711,23 +711,23 @@ smb2_read_data_length(char *buf) static int -smb2_sync_read(const unsigned int xid, struct cifsFileInfo *cfile, +smb2_sync_read(const unsigned int xid, struct cifs_fid *pfid, struct cifs_io_parms *parms, unsigned int *bytes_read, char **buf, int *buf_type) { - parms->persistent_fid = cfile->fid.persistent_fid; - parms->volatile_fid = cfile->fid.volatile_fid; + parms->persistent_fid = pfid->persistent_fid; + parms->volatile_fid = pfid->volatile_fid; return SMB2_read(xid, parms, bytes_read, buf, buf_type); } static int -smb2_sync_write(const unsigned int xid, struct cifsFileInfo *cfile, +smb2_sync_write(const unsigned int xid, struct cifs_fid *pfid, struct cifs_io_parms *parms, unsigned int *written, struct kvec *iov, unsigned long nr_segs) { - parms->persistent_fid = cfile->fid.persistent_fid; - parms->volatile_fid = cfile->fid.volatile_fid; + parms->persistent_fid = pfid->persistent_fid; + parms->volatile_fid = pfid->volatile_fid; return SMB2_write(xid, parms, written, iov, nr_segs); } diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 74b3a66..8f1672b 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1098,6 +1098,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, if (oparms->create_options & CREATE_OPTION_READONLY) file_attributes |= ATTR_READONLY; + if (oparms->create_options & CREATE_OPTION_SPECIAL) + file_attributes |= ATTR_SYSTEM; req->ImpersonationLevel = IL_IMPERSONATION; req->DesiredAccess = cpu_to_le32(oparms->desired_access); -- 1.9.1