diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c index 54bffb2a1786d00c5becdb9c2c275c0aa5f87c99..e6a1fc72018fd1821f8499a70eebe6edd7400bdc 100644 --- a/fs/cifs/smb2file.c +++ b/fs/cifs/smb2file.c @@ -88,14 +88,20 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, } if (buf) { - /* open response does not have IndexNumber field - get it */ - rc = SMB2_get_srv_num(xid, oparms->tcon, fid->persistent_fid, + /* if open response does not have IndexNumber field - get it */ + if (smb2_data->IndexNumber == 0) { + rc = SMB2_get_srv_num(xid, oparms->tcon, + fid->persistent_fid, fid->volatile_fid, &smb2_data->IndexNumber); - if (rc) { - /* let get_inode_info disable server inode numbers */ - smb2_data->IndexNumber = 0; - rc = 0; + if (rc) { + /* + * let get_inode_info disable server inode + * numbers + */ + smb2_data->IndexNumber = 0; + rc = 0; + } } move_smb2_info_to_cifs(buf, smb2_data); } diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index fed75e1646c10e710a2aaedb719f07ecc2f597f0..a5bc1b671c126579a7161853ad0ef352e01f8c39 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -754,11 +754,12 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid) tcon->crfid.is_valid = true; kref_init(&tcon->crfid.refcount); + /* BB TBD check to see if oplock level check can be removed below */ if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) { kref_get(&tcon->crfid.refcount); - oplock = smb2_parse_lease_state(server, o_rsp, - &oparms.fid->epoch, - oparms.fid->lease_key); + smb2_parse_contexts(server, o_rsp, + &oparms.fid->epoch, + oparms.fid->lease_key, &oplock, NULL); } else goto oshr_exit; diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index f58e4dc3987b3fe0cd942cbb8e94c24d4f173478..c8cd7b6cdda2a5c93b0c6a5cf374d6b29291726e 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1873,10 +1873,21 @@ create_reconnect_durable_buf(struct cifs_fid *fid) return buf; } -__u8 -smb2_parse_lease_state(struct TCP_Server_Info *server, +static void +parse_query_id_ctxt(struct create_context *cc, struct smb2_file_all_info *buf) +{ + struct create_on_disk_id *pdisk_id = (struct create_on_disk_id *)cc; + + cifs_dbg(FYI, "parse query id context 0x%llx 0x%llx\n", + pdisk_id->DiskFileId, pdisk_id->VolumeId); + buf->IndexNumber = pdisk_id->DiskFileId; +} + +void +smb2_parse_contexts(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp, - unsigned int *epoch, char *lease_key) + unsigned int *epoch, char *lease_key, __u8 *oplock, + struct smb2_file_all_info *buf) { char *data_offset; struct create_context *cc; @@ -1884,15 +1895,24 @@ smb2_parse_lease_state(struct TCP_Server_Info *server, unsigned int remaining; char *name; + *oplock = 0; data_offset = (char *)rsp + le32_to_cpu(rsp->CreateContextsOffset); remaining = le32_to_cpu(rsp->CreateContextsLength); cc = (struct create_context *)data_offset; + + /* Initialize inode number to 0 in case no valid data in qfid context */ + if (buf) + buf->IndexNumber = 0; + while (remaining >= sizeof(struct create_context)) { name = le16_to_cpu(cc->NameOffset) + (char *)cc; if (le16_to_cpu(cc->NameLength) == 4 && - strncmp(name, "RqLs", 4) == 0) - return server->ops->parse_lease_buf(cc, epoch, - lease_key); + strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4) == 0) + *oplock = server->ops->parse_lease_buf(cc, epoch, + lease_key); + else if (buf && (le16_to_cpu(cc->NameLength) == 4) && + strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4) == 0) + parse_query_id_ctxt(cc, buf); next = le32_to_cpu(cc->Next); if (!next) @@ -1901,7 +1921,10 @@ smb2_parse_lease_state(struct TCP_Server_Info *server, cc = (struct create_context *)((char *)cc + next); } - return 0; + if (rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE) + *oplock = rsp->OplockLevel; + + return; } static int @@ -2588,12 +2611,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, buf->DeletePending = 0; } - if (rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) - *oplock = smb2_parse_lease_state(server, rsp, - &oparms->fid->epoch, - oparms->fid->lease_key); - else - *oplock = rsp->OplockLevel; + + smb2_parse_contexts(server, rsp, &oparms->fid->epoch, + oparms->fid->lease_key, oplock, buf); creat_exit: SMB2_open_free(&rqst); free_rsp_buf(resp_buftype, rsp); diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index 7e2e782f8eddd52aebc7fd156bc62b366316b726..747de9317659198b923b1a850da47bb6641d195c 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -818,7 +818,9 @@ struct durable_reconnect_context_v2 { } __packed; /* See MS-SMB2 2.2.14.2.9 */ -struct on_disk_id { +struct create_on_disk_id { + struct create_context ccontext; + __u8 Name[8]; __le64 DiskFileId; __le64 VolumeId; __u32 Reserved[4]; diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 52df125e918984139b176a5f4101ae6da11c7e0f..07ca72486cfac50f7207487085f68036c4e635c6 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -228,9 +228,10 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *); extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *, enum securityEnum); -extern __u8 smb2_parse_lease_state(struct TCP_Server_Info *server, - struct smb2_create_rsp *rsp, - unsigned int *epoch, char *lease_key); +extern void smb2_parse_contexts(struct TCP_Server_Info *server, + struct smb2_create_rsp *rsp, + unsigned int *epoch, char *lease_key, + __u8 *oplock, struct smb2_file_all_info *buf); extern int smb3_encryption_required(const struct cifs_tcon *tcon); extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length, struct kvec *iov, unsigned int min_buf_size);