Merge tag '6.2-rc-smb3-client-fixes-part1' of git://git.samba.org/sfrench/cifs-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 15 Dec 2022 22:53:14 +0000 (14:53 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 15 Dec 2022 22:53:14 +0000 (14:53 -0800)
Pull cifs client updates from Steve French:

 - SMB3.1.1 POSIX Extensions fixes

 - remove use of generic_writepages() and ->cifs_writepage(), in favor
   of ->cifs_writepages() and ->migrate_folio()

 - memory management fixes

 - mount parm parsing fixes

 - minor cleanup fixes

* tag '6.2-rc-smb3-client-fixes-part1' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: Remove duplicated include in cifsglob.h
  cifs: fix oops during encryption
  cifs: print warning when conflicting soft vs. hard mount options specified
  cifs: fix missing display of three mount options
  cifs: fix various whitespace errors in headers
  cifs: minor cleanup of some headers
  cifs: skip alloc when request has no pages
  cifs: remove ->writepage
  cifs: stop using generic_writepages
  cifs: wire up >migrate_folio
  cifs: Parse owner/group for stat in smb311 posix extensions
  cifs: Add "extbuf" and "extbuflen" args to smb2_compound_op()
  Fix path in cifs/usage.rst

14 files changed:
Documentation/admin-guide/cifs/usage.rst
fs/cifs/cifs_ioctl.h
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/cifsproto.h
fs/cifs/file.c
fs/cifs/fs_context.c
fs/cifs/inode.c
fs/cifs/misc.c
fs/cifs/smb2inode.c
fs/cifs/smb2ops.c
fs/cifs/smb2proto.h

index 3766bf8..ed3b8dc 100644 (file)
@@ -858,7 +858,7 @@ CIFS kernel module parameters
 These module parameters can be specified or modified either during the time of
 module loading or during the runtime by using the interface::
 
-       /proc/module/cifs/parameters/<param>
+       /sys/module/cifs/parameters/<param>
 
 i.e.::
 
index d86d78d..332588e 100644 (file)
@@ -108,7 +108,7 @@ struct smb3_notify_info {
 #define CIFS_IOC_NOTIFY _IOW(CIFS_IOCTL_MAGIC, 9, struct smb3_notify)
 #define CIFS_DUMP_FULL_KEY _IOWR(CIFS_IOCTL_MAGIC, 10, struct smb3_full_key_debug_info)
 #define CIFS_IOC_NOTIFY_INFO _IOWR(CIFS_IOCTL_MAGIC, 11, struct smb3_notify_info)
-#define CIFS_IOC_SHUTDOWN _IOR ('X', 125, __u32)
+#define CIFS_IOC_SHUTDOWN _IOR('X', 125, __u32)
 
 /*
  * Flags for going down operation
index 040267e..914cbb9 100644 (file)
@@ -678,9 +678,15 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
        seq_printf(s, ",echo_interval=%lu",
                        tcon->ses->server->echo_interval / HZ);
 
-       /* Only display max_credits if it was overridden on mount */
+       /* Only display the following if overridden on mount */
        if (tcon->ses->server->max_credits != SMB2_MAX_CREDITS_AVAILABLE)
                seq_printf(s, ",max_credits=%u", tcon->ses->server->max_credits);
+       if (tcon->ses->server->tcp_nodelay)
+               seq_puts(s, ",tcpnodelay");
+       if (tcon->ses->server->noautotune)
+               seq_puts(s, ",noautotune");
+       if (tcon->ses->server->noblocksnd)
+               seq_puts(s, ",noblocksend");
 
        if (tcon->snapshot_time)
                seq_printf(s, ",snapshot=%llu", tcon->snapshot_time);
index 388b745..00a573e 100644 (file)
@@ -105,8 +105,8 @@ extern int cifs_lock(struct file *, int, struct file_lock *);
 extern int cifs_fsync(struct file *, loff_t, loff_t, int);
 extern int cifs_strict_fsync(struct file *, loff_t, loff_t, int);
 extern int cifs_flush(struct file *, fl_owner_t id);
-extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
-extern int cifs_file_strict_mmap(struct file * , struct vm_area_struct *);
+extern int cifs_file_mmap(struct file *file, struct vm_area_struct *vma);
+extern int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma);
 extern const struct file_operations cifs_dir_ops;
 extern int cifs_dir_open(struct inode *inode, struct file *file);
 extern int cifs_readdir(struct file *file, struct dir_context *ctx);
index 1420acf..82f2d30 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/in6.h>
 #include <linux/inet.h>
 #include <linux/slab.h>
+#include <linux/scatterlist.h>
+#include <linux/mm.h>
 #include <linux/mempool.h>
 #include <linux/workqueue.h>
 #include <linux/utsname.h>
@@ -21,7 +23,6 @@
 #include "cifs_fs_sb.h"
 #include "cifsacl.h"
 #include <crypto/internal/hash.h>
-#include <linux/scatterlist.h>
 #include <uapi/linux/cifs/cifs_mount.h>
 #include "../smbfs_common/smb2pdu.h"
 #include "smb2pdu.h"
@@ -785,6 +786,7 @@ static inline unsigned int
 in_flight(struct TCP_Server_Info *server)
 {
        unsigned int num;
+
        spin_lock(&server->req_lock);
        num = server->in_flight;
        spin_unlock(&server->req_lock);
@@ -795,6 +797,7 @@ static inline bool
 has_credits(struct TCP_Server_Info *server, int *credits, int num_credits)
 {
        int num;
+
        spin_lock(&server->req_lock);
        num = *credits;
        spin_unlock(&server->req_lock);
@@ -1025,7 +1028,7 @@ struct cifs_ses {
        struct TCP_Server_Info *server; /* pointer to server info */
        int ses_count;          /* reference counter */
        enum ses_status_enum ses_status;  /* updates protected by cifs_tcp_ses_lock */
-       unsigned overrideSecFlg;  /* if non-zero override global sec flags */
+       unsigned int overrideSecFlg; /* if non-zero override global sec flags */
        char *serverOS;         /* name of operating system underlying server */
        char *serverNOS;        /* name of network operating system of server */
        char *serverDomain;     /* security realm of server */
@@ -1381,7 +1384,7 @@ struct cifsFileInfo {
        __u32 pid;              /* process id who opened file */
        struct cifs_fid fid;    /* file id from remote */
        struct list_head rlist; /* reconnect list */
-       /* BB add lock scope info here if needed */ ;
+       /* BB add lock scope info here if needed */
        /* lock scope id (0 if none) */
        struct dentry *dentry;
        struct tcon_link *tlink;
@@ -1769,6 +1772,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
                                       int number_of_items)
 {
        int i;
+
        if ((number_of_items == 0) || (param == NULL))
                return;
        for (i = 0; i < number_of_items; i++) {
@@ -2137,4 +2141,70 @@ static inline void move_cifs_info_to_smb2(struct smb2_file_all_info *dst, const
        dst->FileNameLength = src->FileNameLength;
 }
 
+static inline unsigned int cifs_get_num_sgs(const struct smb_rqst *rqst,
+                                           int num_rqst,
+                                           const u8 *sig)
+{
+       unsigned int len, skip;
+       unsigned int nents = 0;
+       unsigned long addr;
+       int i, j;
+
+       /* Assumes the first rqst has a transform header as the first iov.
+        * I.e.
+        * rqst[0].rq_iov[0]  is transform header
+        * rqst[0].rq_iov[1+] data to be encrypted/decrypted
+        * rqst[1+].rq_iov[0+] data to be encrypted/decrypted
+        */
+       for (i = 0; i < num_rqst; i++) {
+               /*
+                * The first rqst has a transform header where the
+                * first 20 bytes are not part of the encrypted blob.
+                */
+               for (j = 0; j < rqst[i].rq_nvec; j++) {
+                       struct kvec *iov = &rqst[i].rq_iov[j];
+
+                       skip = (i == 0) && (j == 0) ? 20 : 0;
+                       addr = (unsigned long)iov->iov_base + skip;
+                       if (unlikely(is_vmalloc_addr((void *)addr))) {
+                               len = iov->iov_len - skip;
+                               nents += DIV_ROUND_UP(offset_in_page(addr) + len,
+                                                     PAGE_SIZE);
+                       } else {
+                               nents++;
+                       }
+               }
+               nents += rqst[i].rq_npages;
+       }
+       nents += DIV_ROUND_UP(offset_in_page(sig) + SMB2_SIGNATURE_SIZE, PAGE_SIZE);
+       return nents;
+}
+
+/* We can not use the normal sg_set_buf() as we will sometimes pass a
+ * stack object as buf.
+ */
+static inline struct scatterlist *cifs_sg_set_buf(struct scatterlist *sg,
+                                                 const void *buf,
+                                                 unsigned int buflen)
+{
+       unsigned long addr = (unsigned long)buf;
+       unsigned int off = offset_in_page(addr);
+
+       addr &= PAGE_MASK;
+       if (unlikely(is_vmalloc_addr((void *)addr))) {
+               do {
+                       unsigned int len = min_t(unsigned int, buflen, PAGE_SIZE - off);
+
+                       sg_set_page(sg++, vmalloc_to_page((void *)addr), len, off);
+
+                       off = 0;
+                       addr += PAGE_SIZE;
+                       buflen -= len;
+               } while (buflen);
+       } else {
+               sg_set_page(sg++, virt_to_page(addr), buflen, off);
+       }
+       return sg;
+}
+
 #endif /* _CIFS_GLOB_H */
index d1abaee..623caec 100644 (file)
@@ -1429,7 +1429,7 @@ typedef struct smb_com_transaction_change_notify_req {
        __u8 WatchTree;  /* 1 = Monitor subdirectories */
        __u8 Reserved2;
        __le16 ByteCount;
-/*     __u8 Pad[3];*/
+/*     __u8 Pad[3];*/
 /*     __u8 Data[1];*/
 } __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_REQ;
 
@@ -1752,8 +1752,7 @@ struct smb_com_transaction2_sfi_rsp {
        struct smb_hdr hdr;     /* wct = 10 + SetupCount */
        struct trans2_resp t2;
        __u16 ByteCount;
-       __u16 Reserved2;        /* parameter word reserved -
-                                       present for infolevels > 100 */
+       __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
 } __attribute__((packed));
 
 struct smb_t2_qfi_req {
@@ -1768,8 +1767,7 @@ struct smb_t2_qfi_rsp {
        struct smb_hdr hdr;     /* wct = 10 + SetupCount */
        struct trans2_resp t2;
        __u16 ByteCount;
-       __u16 Reserved2;        /* parameter word reserved -
-                                  present for infolevels > 100 */
+       __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
 } __attribute__((packed));
 
 /*
@@ -2146,13 +2144,11 @@ typedef struct {
 #define CIFS_UNIX_POSIX_PATH_OPS_CAP    0x00000020 /* Allow new POSIX path based
                                                      calls including posix open
                                                      and posix unlink */
-#define CIFS_UNIX_LARGE_READ_CAP        0x00000040 /* support reads >128K (up
-                                                     to 0xFFFF00 */
+#define CIFS_UNIX_LARGE_READ_CAP        0x00000040 /* support reads >128K (up to 0xFFFF00 */
 #define CIFS_UNIX_LARGE_WRITE_CAP       0x00000080
 #define CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP 0x00000100 /* can do SPNEGO crypt */
 #define CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP  0x00000200 /* must do  */
-#define CIFS_UNIX_PROXY_CAP             0x00000400 /* Proxy cap: 0xACE ioctl and
-                                                     QFS PROXY call */
+#define CIFS_UNIX_PROXY_CAP             0x00000400 /* Proxy cap: 0xACE ioctl and QFS PROXY call */
 #ifdef CONFIG_CIFS_POSIX
 /* presumably don't need the 0x20 POSIX_PATH_OPS_CAP since we never send
    LockingX instead of posix locking call on unix sess (and we do not expect
@@ -2368,8 +2364,7 @@ typedef struct {
 
 struct file_allocation_info {
        __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */
-} __attribute__((packed));     /* size used on disk, for level 0x103 for set,
-                                  0x105 for query */
+} __packed; /* size used on disk, for level 0x103 for set, 0x105 for query */
 
 struct file_end_of_file_info {
        __le64 FileSize;                /* offset to end of file */
@@ -2409,8 +2404,7 @@ struct cifs_posix_acl { /* access conrol list  (ACL) */
        __le16  access_entry_count;  /* access ACL - count of entries */
        __le16  default_entry_count; /* default ACL - count of entries */
        struct cifs_posix_ace ace_array[];
-       /* followed by
-       struct cifs_posix_ace default_ace_arraay[] */
+       /* followed by struct cifs_posix_ace default_ace_array[] */
 } __attribute__((packed));  /* level 0x204 */
 
 /* types of access control entries already defined in posix_acl.h */
@@ -2429,17 +2423,17 @@ struct cifs_posix_acl { /* access conrol list  (ACL) */
 /* end of POSIX ACL definitions */
 
 /* POSIX Open Flags */
-#define SMB_O_RDONLY    0x1
-#define SMB_O_WRONLY   0x2
-#define SMB_O_RDWR     0x4
-#define SMB_O_CREAT    0x10
-#define SMB_O_EXCL     0x20
-#define SMB_O_TRUNC    0x40
-#define SMB_O_APPEND   0x80
-#define SMB_O_SYNC     0x100
-#define SMB_O_DIRECTORY 0x200
-#define SMB_O_NOFOLLOW         0x400
-#define SMB_O_DIRECT   0x800
+#define SMB_O_RDONLY   0x1
+#define SMB_O_WRONLY   0x2
+#define SMB_O_RDWR     0x4
+#define SMB_O_CREAT    0x10
+#define SMB_O_EXCL     0x20
+#define SMB_O_TRUNC    0x40
+#define SMB_O_APPEND   0x80
+#define SMB_O_SYNC     0x100
+#define SMB_O_DIRECTORY        0x200
+#define SMB_O_NOFOLLOW 0x400
+#define SMB_O_DIRECT   0x800
 
 typedef struct {
        __le32 OpenFlags; /* same as NT CreateX */
@@ -2716,15 +2710,13 @@ typedef struct file_xattr_info {
        __u32 xattr_value_len;
        char  xattr_name[];
        /* followed by xattr_value[xattr_value_len], no pad */
-} __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute info
-                                             level 0x205 */
+} __packed FILE_XATTR_INFO; /* extended attribute info level 0x205 */
 
 /* flags for lsattr and chflags commands removed arein uapi/linux/fs.h */
 
 typedef struct file_chattr_info {
        __le64  mask; /* list of all possible attribute bits */
        __le64  mode; /* list of actual attribute bits on this inode */
-} __attribute__((packed)) FILE_CHATTR_INFO;  /* ext attributes
-                                               (chattr, chflags) level 0x206 */
-#endif                                 /* POSIX */
+} __packed FILE_CHATTR_INFO;  /* ext attributes (chattr, chflags) level 0x206 */
+#endif                         /* POSIX */
 #endif                         /* _CIFSPDU_H */
index f50f96e..7d4b37e 100644 (file)
@@ -124,7 +124,7 @@ extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
                        struct kvec * /* resp vec */);
 extern int SendReceiveBlockingLock(const unsigned int xid,
                        struct cifs_tcon *ptcon,
-                       struct smb_hdr *in_buf ,
+                       struct smb_hdr *in_buf,
                        struct smb_hdr *out_buf,
                        int *bytes_returned);
 void
@@ -604,8 +604,8 @@ int setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw);
 int cifs_alloc_hash(const char *name, struct shash_desc **sdesc);
 void cifs_free_hash(struct shash_desc **sdesc);
 
-extern void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page,
-                               unsigned int *len, unsigned int *offset);
+void rqst_page_get_length(const struct smb_rqst *rqst, unsigned int page,
+                         unsigned int *len, unsigned int *offset);
 struct cifs_chan *
 cifs_ses_find_chan(struct cifs_ses *ses, struct TCP_Server_Info *server);
 int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses);
index 87b56b1..22dfc1f 100644 (file)
@@ -2646,6 +2646,21 @@ wdata_send_pages(struct cifs_writedata *wdata, unsigned int nr_pages,
        return rc;
 }
 
+static int
+cifs_writepage_locked(struct page *page, struct writeback_control *wbc);
+
+static int cifs_write_one_page(struct page *page, struct writeback_control *wbc,
+               void *data)
+{
+       struct address_space *mapping = data;
+       int ret;
+
+       ret = cifs_writepage_locked(page, wbc);
+       unlock_page(page);
+       mapping_set_error(mapping, ret);
+       return ret;
+}
+
 static int cifs_writepages(struct address_space *mapping,
                           struct writeback_control *wbc)
 {
@@ -2662,10 +2677,11 @@ static int cifs_writepages(struct address_space *mapping,
 
        /*
         * If wsize is smaller than the page cache size, default to writing
-        * one page at a time via cifs_writepage
+        * one page at a time.
         */
        if (cifs_sb->ctx->wsize < PAGE_SIZE)
-               return generic_writepages(mapping, wbc);
+               return write_cache_pages(mapping, wbc, cifs_write_one_page,
+                               mapping);
 
        xid = get_xid();
        if (wbc->range_cyclic) {
@@ -2852,13 +2868,6 @@ retry_write:
        return rc;
 }
 
-static int cifs_writepage(struct page *page, struct writeback_control *wbc)
-{
-       int rc = cifs_writepage_locked(page, wbc);
-       unlock_page(page);
-       return rc;
-}
-
 static int cifs_write_end(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned copied,
                        struct page *page, void *fsdata)
@@ -5231,7 +5240,6 @@ static bool cifs_dirty_folio(struct address_space *mapping, struct folio *folio)
 const struct address_space_operations cifs_addr_ops = {
        .read_folio = cifs_read_folio,
        .readahead = cifs_readahead,
-       .writepage = cifs_writepage,
        .writepages = cifs_writepages,
        .write_begin = cifs_write_begin,
        .write_end = cifs_write_end,
@@ -5240,10 +5248,10 @@ const struct address_space_operations cifs_addr_ops = {
        .direct_IO = cifs_direct_io,
        .invalidate_folio = cifs_invalidate_folio,
        .launder_folio = cifs_launder_folio,
+       .migrate_folio = filemap_migrate_folio,
        /*
-        * TODO: investigate and if useful we could add an cifs_migratePage
-        * helper (under an CONFIG_MIGRATION) in the future, and also
-        * investigate and add an is_dirty_writeback helper if needed
+        * TODO: investigate and if useful we could add an is_dirty_writeback
+        * helper if needed
         */
        .swap_activate = cifs_swap_activate,
        .swap_deactivate = cifs_swap_deactivate,
@@ -5256,7 +5264,6 @@ const struct address_space_operations cifs_addr_ops = {
  */
 const struct address_space_operations cifs_addr_ops_smallbuf = {
        .read_folio = cifs_read_folio,
-       .writepage = cifs_writepage,
        .writepages = cifs_writepages,
        .write_begin = cifs_write_begin,
        .write_end = cifs_write_end,
@@ -5264,4 +5271,5 @@ const struct address_space_operations cifs_addr_ops_smallbuf = {
        .release_folio = cifs_release_folio,
        .invalidate_folio = cifs_invalidate_folio,
        .launder_folio = cifs_launder_folio,
+       .migrate_folio = filemap_migrate_folio,
 };
index 4511959..2c92a82 100644 (file)
@@ -884,16 +884,21 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
                ctx->nodfs = 1;
                break;
        case Opt_hard:
-               if (result.negated)
+               if (result.negated) {
+                       if (ctx->retry == 1)
+                               cifs_dbg(VFS, "conflicting hard vs. soft mount options\n");
                        ctx->retry = 0;
-               else
+               else
                        ctx->retry = 1;
                break;
        case Opt_soft:
                if (result.negated)
                        ctx->retry = 1;
-               else
+               else {
+                       if (ctx->retry == 1)
+                               cifs_dbg(VFS, "conflicting hard vs soft mount options\n");
                        ctx->retry = 0;
+               }
                break;
        case Opt_mapposix:
                if (result.negated)
index 4e2ca3c..286a540 100644 (file)
@@ -632,6 +632,8 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
 
 /* Fill a cifs_fattr struct with info from POSIX info struct */
 static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_info_data *data,
+                                      struct cifs_sid *owner,
+                                      struct cifs_sid *group,
                                       struct super_block *sb, bool adjust_tz, bool symlink)
 {
        struct smb311_posix_qinfo *info = &data->posix_fi;
@@ -680,8 +682,8 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_ope
        }
        /* else if reparse point ... TODO: add support for FIFO and blk dev; special file types */
 
-       fattr->cf_uid = cifs_sb->ctx->linux_uid; /* TODO: map uid and gid from SID */
-       fattr->cf_gid = cifs_sb->ctx->linux_gid;
+       sid_to_id(cifs_sb, owner, fattr, SIDOWNER);
+       sid_to_id(cifs_sb, group, fattr, SIDGROUP);
 
        cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n",
                fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink);
@@ -1175,6 +1177,7 @@ smb311_posix_get_inode_info(struct inode **inode,
        struct cifs_fattr fattr = {0};
        bool symlink = false;
        struct cifs_open_info_data data = {};
+       struct cifs_sid owner, group;
        int rc = 0;
        int tmprc = 0;
 
@@ -1192,7 +1195,8 @@ smb311_posix_get_inode_info(struct inode **inode,
                goto out;
        }
 
-       rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, full_path, &data, &adjust_tz,
+       rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, full_path, &data,
+                                         &owner, &group, &adjust_tz,
                                          &symlink);
 
        /*
@@ -1201,7 +1205,8 @@ smb311_posix_get_inode_info(struct inode **inode,
 
        switch (rc) {
        case 0:
-               smb311_posix_info_to_fattr(&fattr, &data, sb, adjust_tz, symlink);
+               smb311_posix_info_to_fattr(&fattr, &data, &owner, &group,
+                                          sb, adjust_tz, symlink);
                break;
        case -EREMOTE:
                /* DFS link, no metadata available on this server */
index 3e68d82..1cbecd6 100644 (file)
@@ -1136,8 +1136,8 @@ cifs_free_hash(struct shash_desc **sdesc)
  * @len: Where to store the length for this page:
  * @offset: Where to store the offset for this page
  */
-void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page,
-                               unsigned int *len, unsigned int *offset)
+void rqst_page_get_length(const struct smb_rqst *rqst, unsigned int page,
+                         unsigned int *len, unsigned int *offset)
 {
        *len = rqst->rq_pagesz;
        *offset = (page == 0) ? rqst->rq_offset : 0;
index 68e08c8..fbd46db 100644 (file)
@@ -59,6 +59,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                            struct cifs_sb_info *cifs_sb, const char *full_path,
                            __u32 desired_access, __u32 create_disposition, __u32 create_options,
                            umode_t mode, void *ptr, int command, struct cifsFileInfo *cfile,
+                           __u8 **extbuf, size_t *extbuflen,
                            struct kvec *err_iov, int *err_buftype)
 {
        struct cop_vars *vars = NULL;
@@ -430,6 +431,21 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                                &rsp_iov[1], sizeof(idata->posix_fi) /* add SIDs */,
                                (char *)&idata->posix_fi);
                }
+               if (rc == 0) {
+                       unsigned int length = le32_to_cpu(qi_rsp->OutputBufferLength);
+
+                       if (length > sizeof(idata->posix_fi)) {
+                               char *base = (char *)rsp_iov[1].iov_base +
+                                       le16_to_cpu(qi_rsp->OutputBufferOffset) +
+                                       sizeof(idata->posix_fi);
+                               *extbuflen = length - sizeof(idata->posix_fi);
+                               *extbuf = kmemdup(base, *extbuflen, GFP_KERNEL);
+                               if (!*extbuf)
+                                       rc = -ENOMEM;
+                       } else {
+                               rc = -EINVAL;
+                       }
+               }
                if (rqst[1].rq_iov)
                        SMB2_query_info_free(&rqst[1]);
                if (rqst[2].rq_iov)
@@ -539,7 +555,7 @@ int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
        cifs_get_readable_path(tcon, full_path, &cfile);
        rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
                              create_options, ACL_NO_MODE, data, SMB2_OP_QUERY_INFO, cfile,
-                             err_iov, err_buftype);
+                             NULL, NULL, err_iov, err_buftype);
        if (rc == -EOPNOTSUPP) {
                if (err_iov[0].iov_base && err_buftype[0] != CIFS_NO_BUFFER &&
                    ((struct smb2_hdr *)err_iov[0].iov_base)->Command == SMB2_CREATE &&
@@ -555,7 +571,7 @@ int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
                cifs_get_readable_path(tcon, full_path, &cfile);
                rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES,
                                      FILE_OPEN, create_options, ACL_NO_MODE, data,
-                                     SMB2_OP_QUERY_INFO, cfile, NULL, NULL);
+                                     SMB2_OP_QUERY_INFO, cfile, NULL, NULL, NULL, NULL);
        }
 
 out:
@@ -568,13 +584,20 @@ out:
 
 int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
                                 struct cifs_sb_info *cifs_sb, const char *full_path,
-                                struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse)
+                                struct cifs_open_info_data *data,
+                                struct cifs_sid *owner,
+                                struct cifs_sid *group,
+                                bool *adjust_tz, bool *reparse)
 {
        int rc;
        __u32 create_options = 0;
        struct cifsFileInfo *cfile;
        struct kvec err_iov[3] = {};
        int err_buftype[3] = {};
+       __u8 *sidsbuf = NULL;
+       __u8 *sidsbuf_end = NULL;
+       size_t sidsbuflen = 0;
+       size_t owner_len, group_len;
 
        *adjust_tz = false;
        *reparse = false;
@@ -589,7 +612,7 @@ int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
        cifs_get_readable_path(tcon, full_path, &cfile);
        rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
                              create_options, ACL_NO_MODE, data, SMB2_OP_POSIX_QUERY_INFO, cfile,
-                             err_iov, err_buftype);
+                             &sidsbuf, &sidsbuflen, err_iov, err_buftype);
        if (rc == -EOPNOTSUPP) {
                /* BB TODO: When support for special files added to Samba re-verify this path */
                if (err_iov[0].iov_base && err_buftype[0] != CIFS_NO_BUFFER &&
@@ -606,10 +629,31 @@ int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
                cifs_get_readable_path(tcon, full_path, &cfile);
                rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES,
                                      FILE_OPEN, create_options, ACL_NO_MODE, data,
-                                     SMB2_OP_POSIX_QUERY_INFO, cfile, NULL, NULL);
+                                     SMB2_OP_POSIX_QUERY_INFO, cfile,
+                                     &sidsbuf, &sidsbuflen, NULL, NULL);
+       }
+
+       if (rc == 0) {
+               sidsbuf_end = sidsbuf + sidsbuflen;
+
+               owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end);
+               if (owner_len == -1) {
+                       rc = -EINVAL;
+                       goto out;
+               }
+               memcpy(owner, sidsbuf, owner_len);
+
+               group_len = posix_info_sid_size(
+                       sidsbuf + owner_len, sidsbuf_end);
+               if (group_len == -1) {
+                       rc = -EINVAL;
+                       goto out;
+               }
+               memcpy(group, sidsbuf + owner_len, group_len);
        }
 
 out:
+       kfree(sidsbuf);
        free_rsp_buf(err_buftype[0], err_iov[0].iov_base);
        free_rsp_buf(err_buftype[1], err_iov[1].iov_base);
        free_rsp_buf(err_buftype[2], err_iov[2].iov_base);
@@ -624,7 +668,7 @@ smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
        return smb2_compound_op(xid, tcon, cifs_sb, name,
                                FILE_WRITE_ATTRIBUTES, FILE_CREATE,
                                CREATE_NOT_FILE, mode, NULL, SMB2_OP_MKDIR,
-                               NULL, NULL, NULL);
+                               NULL, NULL, NULL, NULL, NULL);
 }
 
 void
@@ -646,7 +690,7 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name,
        tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
                                 FILE_WRITE_ATTRIBUTES, FILE_CREATE,
                                 CREATE_NOT_FILE, ACL_NO_MODE,
-                                &data, SMB2_OP_SET_INFO, cfile, NULL, NULL);
+                                &data, SMB2_OP_SET_INFO, cfile, NULL, NULL, NULL, NULL);
        if (tmprc == 0)
                cifs_i->cifsAttrs = dosattrs;
 }
@@ -658,7 +702,7 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
        drop_cached_dir_by_name(xid, tcon, name, cifs_sb);
        return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
                                CREATE_NOT_FILE, ACL_NO_MODE,
-                               NULL, SMB2_OP_RMDIR, NULL, NULL, NULL);
+                               NULL, SMB2_OP_RMDIR, NULL, NULL, NULL, NULL, NULL);
 }
 
 int
@@ -667,7 +711,7 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
 {
        return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
                                CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
-                               ACL_NO_MODE, NULL, SMB2_OP_DELETE, NULL, NULL, NULL);
+                               ACL_NO_MODE, NULL, SMB2_OP_DELETE, NULL, NULL, NULL, NULL, NULL);
 }
 
 static int
@@ -686,7 +730,7 @@ smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
        }
        rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
                              FILE_OPEN, 0, ACL_NO_MODE, smb2_to_name,
-                             command, cfile, NULL, NULL);
+                             command, cfile, NULL, NULL, NULL, NULL);
 smb2_rename_path:
        kfree(smb2_to_name);
        return rc;
@@ -727,7 +771,7 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
        cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
        return smb2_compound_op(xid, tcon, cifs_sb, full_path,
                                FILE_WRITE_DATA, FILE_OPEN, 0, ACL_NO_MODE,
-                               &eof, SMB2_OP_SET_EOF, cfile, NULL, NULL);
+                               &eof, SMB2_OP_SET_EOF, cfile, NULL, NULL, NULL, NULL);
 }
 
 int
@@ -754,7 +798,7 @@ smb2_set_file_info(struct inode *inode, const char *full_path,
        rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
                              FILE_WRITE_ATTRIBUTES, FILE_OPEN,
                              0, ACL_NO_MODE, buf, SMB2_OP_SET_INFO, cfile,
-                             NULL, NULL);
+                             NULL, NULL, NULL, NULL);
        cifs_put_tlink(tlink);
        return rc;
 }
index 32b3877..d33b00a 100644 (file)
@@ -4204,69 +4204,82 @@ fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len,
        memcpy(&tr_hdr->SessionId, &shdr->SessionId, 8);
 }
 
-/* We can not use the normal sg_set_buf() as we will sometimes pass a
- * stack object as buf.
- */
-static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf,
-                                  unsigned int buflen)
+static void *smb2_aead_req_alloc(struct crypto_aead *tfm, const struct smb_rqst *rqst,
+                                int num_rqst, const u8 *sig, u8 **iv,
+                                struct aead_request **req, struct scatterlist **sgl,
+                                unsigned int *num_sgs)
 {
-       void *addr;
-       /*
-        * VMAP_STACK (at least) puts stack into the vmalloc address space
-        */
-       if (is_vmalloc_addr(buf))
-               addr = vmalloc_to_page(buf);
-       else
-               addr = virt_to_page(buf);
-       sg_set_page(sg, addr, buflen, offset_in_page(buf));
+       unsigned int req_size = sizeof(**req) + crypto_aead_reqsize(tfm);
+       unsigned int iv_size = crypto_aead_ivsize(tfm);
+       unsigned int len;
+       u8 *p;
+
+       *num_sgs = cifs_get_num_sgs(rqst, num_rqst, sig);
+
+       len = iv_size;
+       len += crypto_aead_alignmask(tfm) & ~(crypto_tfm_ctx_alignment() - 1);
+       len = ALIGN(len, crypto_tfm_ctx_alignment());
+       len += req_size;
+       len = ALIGN(len, __alignof__(struct scatterlist));
+       len += *num_sgs * sizeof(**sgl);
+
+       p = kmalloc(len, GFP_ATOMIC);
+       if (!p)
+               return NULL;
+
+       *iv = (u8 *)PTR_ALIGN(p, crypto_aead_alignmask(tfm) + 1);
+       *req = (struct aead_request *)PTR_ALIGN(*iv + iv_size,
+                                               crypto_tfm_ctx_alignment());
+       *sgl = (struct scatterlist *)PTR_ALIGN((u8 *)*req + req_size,
+                                              __alignof__(struct scatterlist));
+       return p;
 }
 
-/* Assumes the first rqst has a transform header as the first iov.
- * I.e.
- * rqst[0].rq_iov[0]  is transform header
- * rqst[0].rq_iov[1+] data to be encrypted/decrypted
- * rqst[1+].rq_iov[0+] data to be encrypted/decrypted
- */
-static struct scatterlist *
-init_sg(int num_rqst, struct smb_rqst *rqst, u8 *sign)
+static void *smb2_get_aead_req(struct crypto_aead *tfm, const struct smb_rqst *rqst,
+                              int num_rqst, const u8 *sig, u8 **iv,
+                              struct aead_request **req, struct scatterlist **sgl)
 {
-       unsigned int sg_len;
+       unsigned int off, len, skip;
        struct scatterlist *sg;
-       unsigned int i;
-       unsigned int j;
-       unsigned int idx = 0;
-       int skip;
-
-       sg_len = 1;
-       for (i = 0; i < num_rqst; i++)
-               sg_len += rqst[i].rq_nvec + rqst[i].rq_npages;
+       unsigned int num_sgs;
+       unsigned long addr;
+       int i, j;
+       void *p;
 
-       sg = kmalloc_array(sg_len, sizeof(struct scatterlist), GFP_KERNEL);
-       if (!sg)
+       p = smb2_aead_req_alloc(tfm, rqst, num_rqst, sig, iv, req, sgl, &num_sgs);
+       if (!p)
                return NULL;
 
-       sg_init_table(sg, sg_len);
+       sg_init_table(*sgl, num_sgs);
+       sg = *sgl;
+
+       /* Assumes the first rqst has a transform header as the first iov.
+        * I.e.
+        * rqst[0].rq_iov[0]  is transform header
+        * rqst[0].rq_iov[1+] data to be encrypted/decrypted
+        * rqst[1+].rq_iov[0+] data to be encrypted/decrypted
+        */
        for (i = 0; i < num_rqst; i++) {
+               /*
+                * The first rqst has a transform header where the
+                * first 20 bytes are not part of the encrypted blob.
+                */
                for (j = 0; j < rqst[i].rq_nvec; j++) {
-                       /*
-                        * The first rqst has a transform header where the
-                        * first 20 bytes are not part of the encrypted blob
-                        */
-                       skip = (i == 0) && (j == 0) ? 20 : 0;
-                       smb2_sg_set_buf(&sg[idx++],
-                                       rqst[i].rq_iov[j].iov_base + skip,
-                                       rqst[i].rq_iov[j].iov_len - skip);
-                       }
+                       struct kvec *iov = &rqst[i].rq_iov[j];
 
+                       skip = (i == 0) && (j == 0) ? 20 : 0;
+                       addr = (unsigned long)iov->iov_base + skip;
+                       len = iov->iov_len - skip;
+                       sg = cifs_sg_set_buf(sg, (void *)addr, len);
+               }
                for (j = 0; j < rqst[i].rq_npages; j++) {
-                       unsigned int len, offset;
-
-                       rqst_page_get_length(&rqst[i], j, &len, &offset);
-                       sg_set_page(&sg[idx++], rqst[i].rq_pages[j], len, offset);
+                       rqst_page_get_length(&rqst[i], j, &len, &off);
+                       sg_set_page(sg++, rqst[i].rq_pages[j], len, off);
                }
        }
-       smb2_sg_set_buf(&sg[idx], sign, SMB2_SIGNATURE_SIZE);
-       return sg;
+       cifs_sg_set_buf(sg, sig, SMB2_SIGNATURE_SIZE);
+
+       return p;
 }
 
 static int
@@ -4314,11 +4327,11 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
        u8 sign[SMB2_SIGNATURE_SIZE] = {};
        u8 key[SMB3_ENC_DEC_KEY_SIZE];
        struct aead_request *req;
-       char *iv;
-       unsigned int iv_len;
+       u8 *iv;
        DECLARE_CRYPTO_WAIT(wait);
        struct crypto_aead *tfm;
        unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
+       void *creq;
 
        rc = smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), enc, key);
        if (rc) {
@@ -4352,32 +4365,15 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
                return rc;
        }
 
-       req = aead_request_alloc(tfm, GFP_KERNEL);
-       if (!req) {
-               cifs_server_dbg(VFS, "%s: Failed to alloc aead request\n", __func__);
+       creq = smb2_get_aead_req(tfm, rqst, num_rqst, sign, &iv, &req, &sg);
+       if (unlikely(!creq))
                return -ENOMEM;
-       }
 
        if (!enc) {
                memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE);
                crypt_len += SMB2_SIGNATURE_SIZE;
        }
 
-       sg = init_sg(num_rqst, rqst, sign);
-       if (!sg) {
-               cifs_server_dbg(VFS, "%s: Failed to init sg\n", __func__);
-               rc = -ENOMEM;
-               goto free_req;
-       }
-
-       iv_len = crypto_aead_ivsize(tfm);
-       iv = kzalloc(iv_len, GFP_KERNEL);
-       if (!iv) {
-               cifs_server_dbg(VFS, "%s: Failed to alloc iv\n", __func__);
-               rc = -ENOMEM;
-               goto free_sg;
-       }
-
        if ((server->cipher_type == SMB2_ENCRYPTION_AES128_GCM) ||
            (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
                memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES_GCM_NONCE);
@@ -4386,6 +4382,7 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
                memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES_CCM_NONCE);
        }
 
+       aead_request_set_tfm(req, tfm);
        aead_request_set_crypt(req, sg, sg, crypt_len, iv);
        aead_request_set_ad(req, assoc_data_len);
 
@@ -4398,11 +4395,7 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
        if (!rc && enc)
                memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE);
 
-       kfree_sensitive(iv);
-free_sg:
-       kfree_sensitive(sg);
-free_req:
-       kfree_sensitive(req);
+       kfree_sensitive(creq);
        return rc;
 }
 
@@ -4445,21 +4438,27 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
        int rc = -ENOMEM;
 
        for (i = 1; i < num_rqst; i++) {
-               npages = old_rq[i - 1].rq_npages;
+               struct smb_rqst *old = &old_rq[i - 1];
+               struct smb_rqst *new = &new_rq[i];
+
+               orig_len += smb_rqst_len(server, old);
+               new->rq_iov = old->rq_iov;
+               new->rq_nvec = old->rq_nvec;
+
+               npages = old->rq_npages;
+               if (!npages)
+                       continue;
+
                pages = kmalloc_array(npages, sizeof(struct page *),
                                      GFP_KERNEL);
                if (!pages)
                        goto err_free;
 
-               new_rq[i].rq_pages = pages;
-               new_rq[i].rq_npages = npages;
-               new_rq[i].rq_offset = old_rq[i - 1].rq_offset;
-               new_rq[i].rq_pagesz = old_rq[i - 1].rq_pagesz;
-               new_rq[i].rq_tailsz = old_rq[i - 1].rq_tailsz;
-               new_rq[i].rq_iov = old_rq[i - 1].rq_iov;
-               new_rq[i].rq_nvec = old_rq[i - 1].rq_nvec;
-
-               orig_len += smb_rqst_len(server, &old_rq[i - 1]);
+               new->rq_pages = pages;
+               new->rq_npages = npages;
+               new->rq_offset = old->rq_offset;
+               new->rq_pagesz = old->rq_pagesz;
+               new->rq_tailsz = old->rq_tailsz;
 
                for (j = 0; j < npages; j++) {
                        pages[j] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
@@ -4472,14 +4471,14 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
                        char *dst, *src;
                        unsigned int offset, len;
 
-                       rqst_page_get_length(&new_rq[i], j, &len, &offset);
+                       rqst_page_get_length(new, j, &len, &offset);
 
-                       dst = (char *) kmap(new_rq[i].rq_pages[j]) + offset;
-                       src = (char *) kmap(old_rq[i - 1].rq_pages[j]) + offset;
+                       dst = kmap_local_page(new->rq_pages[j]) + offset;
+                       src = kmap_local_page(old->rq_pages[j]) + offset;
 
                        memcpy(dst, src, len);
-                       kunmap(new_rq[i].rq_pages[j]);
-                       kunmap(old_rq[i - 1].rq_pages[j]);
+                       kunmap(new->rq_pages[j]);
+                       kunmap(old->rq_pages[j]);
                }
        }
 
index be21b5d..d5d7ffb 100644 (file)
@@ -277,7 +277,10 @@ extern int smb2_query_info_compound(const unsigned int xid,
 /* query path info from the server using SMB311 POSIX extensions*/
 int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
                                 struct cifs_sb_info *cifs_sb, const char *full_path,
-                                struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse);
+                                struct cifs_open_info_data *data,
+                                struct cifs_sid *owner,
+                                struct cifs_sid *group,
+                                bool *adjust_tz, bool *reparse);
 int posix_info_parse(const void *beg, const void *end,
                     struct smb2_posix_info_parsed *out);
 int posix_info_sid_size(const void *beg, const void *end);