Merge tag '5.5-rc-smb3-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 8 Dec 2019 20:12:18 +0000 (12:12 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 8 Dec 2019 20:12:18 +0000 (12:12 -0800)
Pull cifs fixes from Steve French:
 "Nine cifs/smb3 fixes:

   - one fix for stable (oops during oplock break)

   - two timestamp fixes including important one for updating mtime at
     close to avoid stale metadata caching issue on dirty files (also
     improves perf by using SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB over the
     wire)

   - two fixes for "modefromsid" mount option for file create (now
     allows mode bits to be set more atomically and accurately on create
     by adding "sd_context" on create when modefromsid specified on
     mount)

   - two fixes for multichannel found in testing this week against
     different servers

   - two small cleanup patches"

* tag '5.5-rc-smb3-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6:
  smb3: improve check for when we send the security descriptor context on create
  smb3: fix mode passed in on create for modetosid mount option
  cifs: fix possible uninitialized access and race on iface_list
  cifs: Fix lookup of SMB connections on multichannel
  smb3: query attributes on file close
  smb3: remove unused flag passed into close functions
  cifs: remove redundant assignment to pointer pneg_ctxt
  fs: cifs: Fix atime update check vs mtime
  CIFS: Fix NULL-pointer dereference in smb2_push_mandatory_locks

13 files changed:
fs/cifs/cifsacl.c
fs/cifs/cifsacl.h
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/sess.c
fs/cifs/smb2inode.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2pdu.h
fs/cifs/smb2proto.h

index 06ffe52..96ae72b 100644 (file)
@@ -802,6 +802,31 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
        return;
 }
 
+/*
+ * Fill in the special SID based on the mode. See
+ * http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
+ */
+unsigned int setup_special_mode_ACE(struct cifs_ace *pntace, __u64 nmode)
+{
+       int i;
+       unsigned int ace_size = 28;
+
+       pntace->type = ACCESS_DENIED_ACE_TYPE;
+       pntace->flags = 0x0;
+       pntace->access_req = 0;
+       pntace->sid.num_subauth = 3;
+       pntace->sid.revision = 1;
+       for (i = 0; i < NUM_AUTHS; i++)
+               pntace->sid.authority[i] = sid_unix_NFS_mode.authority[i];
+
+       pntace->sid.sub_auth[0] = sid_unix_NFS_mode.sub_auth[0];
+       pntace->sid.sub_auth[1] = sid_unix_NFS_mode.sub_auth[1];
+       pntace->sid.sub_auth[2] = cpu_to_le32(nmode & 07777);
+
+       /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
+       pntace->size = cpu_to_le16(ace_size);
+       return ace_size;
+}
 
 static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
                        struct cifs_sid *pgrpsid, __u64 nmode, bool modefromsid)
@@ -815,23 +840,8 @@ static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
        if (modefromsid) {
                struct cifs_ace *pntace =
                        (struct cifs_ace *)((char *)pnndacl + size);
-               int i;
 
-               pntace->type = ACCESS_ALLOWED;
-               pntace->flags = 0x0;
-               pntace->access_req = 0;
-               pntace->sid.num_subauth = 3;
-               pntace->sid.revision = 1;
-               for (i = 0; i < NUM_AUTHS; i++)
-                       pntace->sid.authority[i] =
-                               sid_unix_NFS_mode.authority[i];
-               pntace->sid.sub_auth[0] = sid_unix_NFS_mode.sub_auth[0];
-               pntace->sid.sub_auth[1] = sid_unix_NFS_mode.sub_auth[1];
-               pntace->sid.sub_auth[2] = cpu_to_le32(nmode & 07777);
-
-               /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
-               pntace->size = cpu_to_le16(28);
-               size += 28;
+               size += setup_special_mode_ACE(pntace, nmode);
                num_aces++;
        }
 
index 439b99c..21d7dee 100644 (file)
@@ -147,22 +147,22 @@ struct smb3_sd {
 } __packed;
 
 /* Meaning of 'Control' field flags */
-#define ACL_CONTROL_SR 0x0001  /* Self relative */
-#define ACL_CONTROL_RM 0x0002  /* Resource manager control bits */
-#define ACL_CONTROL_PS 0x0004  /* SACL protected from inherits */
-#define ACL_CONTROL_PD 0x0008  /* DACL protected from inherits */
-#define ACL_CONTROL_SI 0x0010  /* SACL Auto-Inherited */
-#define ACL_CONTROL_DI 0x0020  /* DACL Auto-Inherited */
-#define ACL_CONTROL_SC 0x0040  /* SACL computed through inheritance */
-#define ACL_CONTROL_DC 0x0080  /* DACL computed through inheritence */
-#define ACL_CONTROL_SS 0x0100  /* Create server ACL */
-#define ACL_CONTROL_DT 0x0200  /* DACL provided by trusteed source */
-#define ACL_CONTROL_SD 0x0400  /* SACL defaulted */
-#define ACL_CONTROL_SP 0x0800  /* SACL is present on object */
-#define ACL_CONTROL_DD 0x1000  /* DACL defaulted */
-#define ACL_CONTROL_DP 0x2000  /* DACL is present on object */
-#define ACL_CONTROL_GD 0x4000  /* Group was defaulted */
-#define ACL_CONTROL_OD 0x8000  /* User was defaulted */
+#define ACL_CONTROL_SR 0x8000  /* Self relative */
+#define ACL_CONTROL_RM 0x4000  /* Resource manager control bits */
+#define ACL_CONTROL_PS 0x2000  /* SACL protected from inherits */
+#define ACL_CONTROL_PD 0x1000  /* DACL protected from inherits */
+#define ACL_CONTROL_SI 0x0800  /* SACL Auto-Inherited */
+#define ACL_CONTROL_DI 0x0400  /* DACL Auto-Inherited */
+#define ACL_CONTROL_SC 0x0200  /* SACL computed through inheritance */
+#define ACL_CONTROL_DC 0x0100  /* DACL computed through inheritence */
+#define ACL_CONTROL_SS 0x0080  /* Create server ACL */
+#define ACL_CONTROL_DT 0x0040  /* DACL provided by trusted source */
+#define ACL_CONTROL_SD 0x0020  /* SACL defaulted */
+#define ACL_CONTROL_SP 0x0010  /* SACL is present on object */
+#define ACL_CONTROL_DD 0x0008  /* DACL defaulted */
+#define ACL_CONTROL_DP 0x0004  /* DACL is present on object */
+#define ACL_CONTROL_GD 0x0002  /* Group was defaulted */
+#define ACL_CONTROL_OD 0x0001  /* User was defaulted */
 
 /* Meaning of AclRevision flags */
 #define ACL_REVISION   0x02 /* See section 2.4.4.1 of MS-DTYP */
index d34a4ed..fd0262c 100644 (file)
@@ -368,6 +368,9 @@ struct smb_version_operations {
        /* close a file */
        void (*close)(const unsigned int, struct cifs_tcon *,
                      struct cifs_fid *);
+       /* close a file, returning file attributes and timestamps */
+       void (*close_getattr)(const unsigned int xid, struct cifs_tcon *tcon,
+                     struct cifsFileInfo *pfile_info);
        /* send a flush request to the server */
        int (*flush)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
        /* async read from the server */
@@ -774,6 +777,7 @@ struct TCP_Server_Info {
         */
        int nr_targets;
        bool noblockcnt; /* use non-blocking connect() */
+       bool is_channel; /* if a session channel */
 };
 
 struct cifs_credits {
index 1ed6953..9c22940 100644 (file)
@@ -213,6 +213,7 @@ extern struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *,
                                                const struct cifs_fid *, u32 *);
 extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
                                const char *, int);
+extern unsigned int setup_special_mode_ACE(struct cifs_ace *pace, __u64 nmode);
 
 extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);
 extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
index 86d1bae..05ea0e2 100644 (file)
@@ -2712,7 +2712,11 @@ cifs_find_tcp_session(struct smb_vol *vol)
 
        spin_lock(&cifs_tcp_ses_lock);
        list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
-               if (!match_server(server, vol))
+               /*
+                * Skip ses channels since they're only handled in lower layers
+                * (e.g. cifs_send_recv).
+                */
+               if (server->is_channel || !match_server(server, vol))
                        continue;
 
                ++server->srv_count;
index f1fe9c4..043288b 100644 (file)
@@ -315,9 +315,6 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
        INIT_LIST_HEAD(&fdlocks->locks);
        fdlocks->cfile = cfile;
        cfile->llist = fdlocks;
-       cifs_down_write(&cinode->lock_sem);
-       list_add(&fdlocks->llist, &cinode->llist);
-       up_write(&cinode->lock_sem);
 
        cfile->count = 1;
        cfile->pid = current->tgid;
@@ -342,6 +339,10 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
                oplock = 0;
        }
 
+       cifs_down_write(&cinode->lock_sem);
+       list_add(&fdlocks->llist, &cinode->llist);
+       up_write(&cinode->lock_sem);
+
        spin_lock(&tcon->open_file_lock);
        if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock)
                oplock = fid->pending_open->oplock;
@@ -495,7 +496,9 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file,
                unsigned int xid;
 
                xid = get_xid();
-               if (server->ops->close)
+               if (server->ops->close_getattr)
+                       server->ops->close_getattr(xid, tcon, cifs_file);
+               else if (server->ops->close)
                        server->ops->close(xid, tcon, &cifs_file->fid);
                _free_xid(xid);
        }
index 8a76195..ca76a92 100644 (file)
@@ -163,7 +163,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
 
        spin_lock(&inode->i_lock);
        /* we do not want atime to be less than mtime, it broke some apps */
-       if (timespec64_compare(&fattr->cf_atime, &fattr->cf_mtime))
+       if (timespec64_compare(&fattr->cf_atime, &fattr->cf_mtime) < 0)
                inode->i_atime = fattr->cf_mtime;
        else
                inode->i_atime = fattr->cf_atime;
index fb3bdc4..f0795c8 100644 (file)
@@ -77,6 +77,8 @@ int cifs_try_adding_channels(struct cifs_ses *ses)
        int i = 0;
        int rc = 0;
        int tries = 0;
+       struct cifs_server_iface *ifaces = NULL;
+       size_t iface_count;
 
        if (left <= 0) {
                cifs_dbg(FYI,
@@ -91,6 +93,26 @@ int cifs_try_adding_channels(struct cifs_ses *ses)
        }
 
        /*
+        * Make a copy of the iface list at the time and use that
+        * instead so as to not hold the iface spinlock for opening
+        * channels
+        */
+       spin_lock(&ses->iface_lock);
+       iface_count = ses->iface_count;
+       if (iface_count <= 0) {
+               spin_unlock(&ses->iface_lock);
+               cifs_dbg(FYI, "no iface list available to open channels\n");
+               return 0;
+       }
+       ifaces = kmemdup(ses->iface_list, iface_count*sizeof(*ifaces),
+                        GFP_ATOMIC);
+       if (!ifaces) {
+               spin_unlock(&ses->iface_lock);
+               return 0;
+       }
+       spin_unlock(&ses->iface_lock);
+
+       /*
         * Keep connecting to same, fastest, iface for all channels as
         * long as its RSS. Try next fastest one if not RSS or channel
         * creation fails.
@@ -105,9 +127,9 @@ int cifs_try_adding_channels(struct cifs_ses *ses)
                        break;
                }
 
-               iface = &ses->iface_list[i];
+               iface = &ifaces[i];
                if (is_ses_using_iface(ses, iface) && !iface->rss_capable) {
-                       i = (i+1) % ses->iface_count;
+                       i = (i+1) % iface_count;
                        continue;
                }
 
@@ -115,7 +137,7 @@ int cifs_try_adding_channels(struct cifs_ses *ses)
                if (rc) {
                        cifs_dbg(FYI, "failed to open extra channel on iface#%d rc=%d\n",
                                 i, rc);
-                       i = (i+1) % ses->iface_count;
+                       i = (i+1) % iface_count;
                        continue;
                }
 
@@ -124,6 +146,7 @@ int cifs_try_adding_channels(struct cifs_ses *ses)
                left--;
        }
 
+       kfree(ifaces);
        return ses->chan_count - old_chan_count;
 }
 
@@ -213,6 +236,9 @@ cifs_ses_add_channel(struct cifs_ses *ses, struct cifs_server_iface *iface)
                chan->server = NULL;
                goto out;
        }
+       spin_lock(&cifs_tcp_ses_lock);
+       chan->server->is_channel = true;
+       spin_unlock(&cifs_tcp_ses_lock);
 
        /*
         * We need to allocate the server crypto now as we will need
index 4121ac1..18c7a33 100644 (file)
@@ -313,7 +313,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
        rqst[num_rqst].rq_iov = close_iov;
        rqst[num_rqst].rq_nvec = 1;
        rc = SMB2_close_init(tcon, &rqst[num_rqst], COMPOUND_FID,
-                            COMPOUND_FID);
+                            COMPOUND_FID, false);
        smb2_set_related(&rqst[num_rqst]);
        if (rc)
                goto finished;
index a7f328f..a5c96bc 100644 (file)
@@ -1178,7 +1178,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
        memset(&close_iov, 0, sizeof(close_iov));
        rqst[2].rq_iov = close_iov;
        rqst[2].rq_nvec = 1;
-       rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
+       rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
        smb2_set_related(&rqst[2]);
 
        rc = compound_send_recv(xid, ses, flags, 3, rqst,
@@ -1332,6 +1332,45 @@ smb2_close_file(const unsigned int xid, struct cifs_tcon *tcon,
        SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
 }
 
+static void
+smb2_close_getattr(const unsigned int xid, struct cifs_tcon *tcon,
+                  struct cifsFileInfo *cfile)
+{
+       struct smb2_file_network_open_info file_inf;
+       struct inode *inode;
+       int rc;
+
+       rc = __SMB2_close(xid, tcon, cfile->fid.persistent_fid,
+                  cfile->fid.volatile_fid, &file_inf);
+       if (rc)
+               return;
+
+       inode = d_inode(cfile->dentry);
+
+       spin_lock(&inode->i_lock);
+       CIFS_I(inode)->time = jiffies;
+
+       /* Creation time should not need to be updated on close */
+       if (file_inf.LastWriteTime)
+               inode->i_mtime = cifs_NTtimeToUnix(file_inf.LastWriteTime);
+       if (file_inf.ChangeTime)
+               inode->i_ctime = cifs_NTtimeToUnix(file_inf.ChangeTime);
+       if (file_inf.LastAccessTime)
+               inode->i_atime = cifs_NTtimeToUnix(file_inf.LastAccessTime);
+
+       /*
+        * i_blocks is not related to (i_size / i_blksize),
+        * but instead 512 byte (2**9) size is required for
+        * calculating num blocks.
+        */
+       if (le64_to_cpu(file_inf.AllocationSize) > 4096)
+               inode->i_blocks =
+                       (512 - 1 + le64_to_cpu(file_inf.AllocationSize)) >> 9;
+
+       /* End of file and Attributes should not have to be updated on close */
+       spin_unlock(&inode->i_lock);
+}
+
 static int
 SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,
                     u64 persistent_fid, u64 volatile_fid,
@@ -1512,7 +1551,7 @@ smb2_ioctl_query_info(const unsigned int xid,
        rqst[2].rq_iov = close_iov;
        rqst[2].rq_nvec = 1;
 
-       rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
+       rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
        if (rc)
                goto iqinf_exit;
        smb2_set_related(&rqst[2]);
@@ -2241,7 +2280,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
        rqst[2].rq_iov = close_iov;
        rqst[2].rq_nvec = 1;
 
-       rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
+       rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
        if (rc)
                goto qic_exit;
        smb2_set_related(&rqst[2]);
@@ -2654,7 +2693,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
        rqst[2].rq_iov = close_iov;
        rqst[2].rq_nvec = 1;
 
-       rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
+       rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
        if (rc)
                goto querty_exit;
 
@@ -4707,6 +4746,7 @@ struct smb_version_operations smb30_operations = {
        .open = smb2_open_file,
        .set_fid = smb2_set_fid,
        .close = smb2_close_file,
+       .close_getattr = smb2_close_getattr,
        .flush = smb2_flush_file,
        .async_readv = smb2_async_readv,
        .async_writev = smb2_async_writev,
@@ -4816,6 +4856,7 @@ struct smb_version_operations smb311_operations = {
        .open = smb2_open_file,
        .set_fid = smb2_set_fid,
        .close = smb2_close_file,
+       .close_getattr = smb2_close_getattr,
        .flush = smb2_flush_file,
        .async_readv = smb2_async_readv,
        .async_writev = smb2_async_writev,
index ed77f94..0ab6b12 100644 (file)
@@ -554,7 +554,7 @@ static void
 assemble_neg_contexts(struct smb2_negotiate_req *req,
                      struct TCP_Server_Info *server, unsigned int *total_len)
 {
-       char *pneg_ctxt = (char *)req;
+       char *pneg_ctxt;
        unsigned int ctxt_len;
 
        if (*total_len > 200) {
@@ -2191,6 +2191,72 @@ add_twarp_context(struct kvec *iov, unsigned int *num_iovec, __u64 timewarp)
        return 0;
 }
 
+/* See MS-SMB2 2.2.13.2.2 and MS-DTYP 2.4.6 */
+static struct crt_sd_ctxt *
+create_sd_buf(umode_t mode, unsigned int *len)
+{
+       struct crt_sd_ctxt *buf;
+       struct cifs_ace *pace;
+       unsigned int sdlen, acelen;
+
+       *len = roundup(sizeof(struct crt_sd_ctxt) + sizeof(struct cifs_ace), 8);
+       buf = kzalloc(*len, GFP_KERNEL);
+       if (buf == NULL)
+               return buf;
+
+       sdlen = sizeof(struct smb3_sd) + sizeof(struct smb3_acl) +
+                sizeof(struct cifs_ace);
+
+       buf->ccontext.DataOffset = cpu_to_le16(offsetof
+                                       (struct crt_sd_ctxt, sd));
+       buf->ccontext.DataLength = cpu_to_le32(sdlen);
+       buf->ccontext.NameOffset = cpu_to_le16(offsetof
+                               (struct crt_sd_ctxt, Name));
+       buf->ccontext.NameLength = cpu_to_le16(4);
+       /* SMB2_CREATE_SD_BUFFER_TOKEN is "SecD" */
+       buf->Name[0] = 'S';
+       buf->Name[1] = 'e';
+       buf->Name[2] = 'c';
+       buf->Name[3] = 'D';
+       buf->sd.Revision = 1;  /* Must be one see MS-DTYP 2.4.6 */
+       /*
+        * ACL is "self relative" ie ACL is stored in contiguous block of memory
+        * and "DP" ie the DACL is present
+        */
+       buf->sd.Control = cpu_to_le16(ACL_CONTROL_SR | ACL_CONTROL_DP);
+
+       /* offset owner, group and Sbz1 and SACL are all zero */
+       buf->sd.OffsetDacl = cpu_to_le32(sizeof(struct smb3_sd));
+       buf->acl.AclRevision = ACL_REVISION; /* See 2.4.4.1 of MS-DTYP */
+
+       /* create one ACE to hold the mode embedded in reserved special SID */
+       pace = (struct cifs_ace *)(sizeof(struct crt_sd_ctxt) + (char *)buf);
+       acelen = setup_special_mode_ACE(pace, (__u64)mode);
+       buf->acl.AclSize = cpu_to_le16(sizeof(struct cifs_acl) + acelen);
+       buf->acl.AceCount = cpu_to_le16(1);
+       return buf;
+}
+
+static int
+add_sd_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
+{
+       struct smb2_create_req *req = iov[0].iov_base;
+       unsigned int num = *num_iovec;
+       unsigned int len = 0;
+
+       iov[num].iov_base = create_sd_buf(mode, &len);
+       if (iov[num].iov_base == NULL)
+               return -ENOMEM;
+       iov[num].iov_len = len;
+       if (!req->CreateContextsOffset)
+               req->CreateContextsOffset = cpu_to_le32(
+                               sizeof(struct smb2_create_req) +
+                               iov[num - 1].iov_len);
+       le32_add_cpu(&req->CreateContextsLength, len);
+       *num_iovec = num + 1;
+       return 0;
+}
+
 static struct crt_query_id_ctxt *
 create_query_id_buf(void)
 {
@@ -2563,7 +2629,9 @@ SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock,
                        return rc;
        }
 
-       if ((oparms->disposition == FILE_CREATE) &&
+       if ((oparms->disposition != FILE_OPEN) &&
+           (oparms->cifs_sb) &&
+           (oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) &&
            (oparms->mode != ACL_NO_MODE)) {
                if (n_iov > 2) {
                        struct create_context *ccontext =
@@ -2572,7 +2640,8 @@ SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock,
                                cpu_to_le32(iov[n_iov-1].iov_len);
                }
 
-               /* rc = add_sd_context(iov, &n_iov, oparms->mode); */
+               cifs_dbg(FYI, "add sd with mode 0x%x\n", oparms->mode);
+               rc = add_sd_context(iov, &n_iov, oparms->mode);
                if (rc)
                        return rc;
        }
@@ -2932,7 +3001,7 @@ SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
 
 int
 SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
-               u64 persistent_fid, u64 volatile_fid)
+               u64 persistent_fid, u64 volatile_fid, bool query_attrs)
 {
        struct smb2_close_req *req;
        struct kvec *iov = rqst->rq_iov;
@@ -2945,6 +3014,10 @@ SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
 
        req->PersistentFileId = persistent_fid;
        req->VolatileFileId = volatile_fid;
+       if (query_attrs)
+               req->Flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB;
+       else
+               req->Flags = 0;
        iov[0].iov_base = (char *)req;
        iov[0].iov_len = total_len;
 
@@ -2959,8 +3032,9 @@ SMB2_close_free(struct smb_rqst *rqst)
 }
 
 int
-SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
-                u64 persistent_fid, u64 volatile_fid, int flags)
+__SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
+            u64 persistent_fid, u64 volatile_fid,
+            struct smb2_file_network_open_info *pbuf)
 {
        struct smb_rqst rqst;
        struct smb2_close_rsp *rsp = NULL;
@@ -2969,6 +3043,8 @@ SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
        struct kvec rsp_iov;
        int resp_buftype = CIFS_NO_BUFFER;
        int rc = 0;
+       int flags = 0;
+       bool query_attrs = false;
 
        cifs_dbg(FYI, "Close\n");
 
@@ -2983,8 +3059,13 @@ SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
        rqst.rq_iov = iov;
        rqst.rq_nvec = 1;
 
+       /* check if need to ask server to return timestamps in close response */
+       if (pbuf)
+               query_attrs = true;
+
        trace_smb3_close_enter(xid, persistent_fid, tcon->tid, ses->Suid);
-       rc = SMB2_close_init(tcon, &rqst, persistent_fid, volatile_fid);
+       rc = SMB2_close_init(tcon, &rqst, persistent_fid, volatile_fid,
+                            query_attrs);
        if (rc)
                goto close_exit;
 
@@ -2996,42 +3077,43 @@ SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
                trace_smb3_close_err(xid, persistent_fid, tcon->tid, ses->Suid,
                                     rc);
                goto close_exit;
-       } else
+       } else {
                trace_smb3_close_done(xid, persistent_fid, tcon->tid,
                                      ses->Suid);
+               /*
+                * Note that have to subtract 4 since struct network_open_info
+                * has a final 4 byte pad that close response does not have
+                */
+               if (pbuf)
+                       memcpy(pbuf, (char *)&rsp->CreationTime, sizeof(*pbuf) - 4);
+       }
 
        atomic_dec(&tcon->num_remote_opens);
-
-       /* BB FIXME - decode close response, update inode for caching */
-
 close_exit:
        SMB2_close_free(&rqst);
        free_rsp_buf(resp_buftype, rsp);
-       return rc;
-}
-
-int
-SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
-          u64 persistent_fid, u64 volatile_fid)
-{
-       int rc;
-       int tmp_rc;
-
-       rc = SMB2_close_flags(xid, tcon, persistent_fid, volatile_fid, 0);
 
        /* retry close in a worker thread if this one is interrupted */
        if (rc == -EINTR) {
+               int tmp_rc;
+
                tmp_rc = smb2_handle_cancelled_close(tcon, persistent_fid,
                                                     volatile_fid);
                if (tmp_rc)
                        cifs_dbg(VFS, "handle cancelled close fid 0x%llx returned error %d\n",
                                 persistent_fid, tmp_rc);
        }
-
        return rc;
 }
 
 int
+SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
+               u64 persistent_fid, u64 volatile_fid)
+{
+       return __SMB2_close(xid, tcon, persistent_fid, volatile_fid, NULL);
+}
+
+int
 smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
                  struct kvec *iov, unsigned int min_buf_size)
 {
index f264e1d..7b1c379 100644 (file)
@@ -25,6 +25,7 @@
 #define _SMB2PDU_H
 
 #include <net/sock.h>
+#include <cifsacl.h>
 
 /*
  * Note that, due to trying to use names similar to the protocol specifications,
@@ -855,6 +856,15 @@ struct crt_query_id_ctxt {
        __u8    Name[8];
 } __packed;
 
+struct crt_sd_ctxt {
+       struct create_context ccontext;
+       __u8    Name[8];
+       struct smb3_sd sd;
+       struct smb3_acl acl;
+       /* Followed by at least 4 ACEs */
+} __packed;
+
+
 #define COPY_CHUNK_RES_KEY_SIZE        24
 struct resume_key_req {
        char ResumeKey[COPY_CHUNK_RES_KEY_SIZE];
@@ -1570,6 +1580,17 @@ struct smb2_file_eof_info { /* encoding of request for level 10 */
        __le64 EndOfFile; /* new end of file value */
 } __packed; /* level 20 Set */
 
+struct smb2_file_network_open_info {
+       __le64 CreationTime;
+       __le64 LastAccessTime;
+       __le64 LastWriteTime;
+       __le64 ChangeTime;
+       __le64 AllocationSize;
+       __le64 EndOfFile;
+       __le32 Attributes;
+       __le32 Reserved;
+} __packed; /* level 34 Query also similar returned in close rsp and open rsp */
+
 extern char smb2_padding[7];
 
 #endif                         /* _SMB2PDU_H */
index d21a5fc..a18272c 100644 (file)
@@ -155,12 +155,13 @@ extern int SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
                        u64 persistent_fid, u64 volatile_fid, bool watch_tree,
                        u32 completion_filter);
 
+extern int __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
+                       u64 persistent_fid, u64 volatile_fid,
+                       struct smb2_file_network_open_info *pbuf);
 extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
                      u64 persistent_file_id, u64 volatile_file_id);
-extern int SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
-                           u64 persistent_fid, u64 volatile_fid, int flags);
 extern int SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
-                     u64 persistent_file_id, u64 volatile_file_id);
+                     u64 persistent_fid, u64 volatile_fid, bool query_attrs);
 extern void SMB2_close_free(struct smb_rqst *rqst);
 extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
                      u64 persistent_file_id, u64 volatile_file_id);