From: Pavel Shilovsky <[email protected]>
Signed-off-by: Pavel Shilovsky <[email protected]>
---
fs/cifs/cifsglob.h | 3 +
fs/cifs/cifsproto.h | 4 +-
fs/cifs/connect.c | 2 +-
fs/cifs/file.c | 24 +++++--
fs/cifs/misc.c | 11 ++-
fs/cifs/smb2file.c | 39 ++++++------
fs/cifs/smb2misc.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++-
fs/cifs/smb2pdu.c | 90 ++++++++++++++++++++------
fs/cifs/smb2pdu.h | 35 ++++++++++
fs/cifs/smb2proto.h | 14 +++-
10 files changed, 348 insertions(+), 54 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 3d950d9..56962a5 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -697,6 +697,9 @@ struct cifsInodeInfo {
#endif
};
+typedef int (oplock_callback_t)(struct cifs_tcon *, struct cifsInodeInfo *,
+ struct cifsFileInfo *);
+
static inline struct cifsInodeInfo *
CIFS_I(struct inode *inode)
{
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 4f1045b..a61da92 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -94,7 +94,7 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
struct smb_hdr *out_buf,
int *bytes_returned);
extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
-extern bool is_valid_oplock_break(struct smb_hdr *smb,
+extern bool is_valid_oplock_break(char *buffer,
struct TCP_Server_Info *);
extern bool backup_cred(struct cifs_sb_info *);
extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
@@ -132,6 +132,8 @@ extern struct cifsFileInfo *cifs_new_fileinfo(__u16 netfid,
struct file *file,
__u32 oplock);
extern struct cifsFileInfo *cifs_new_fileinfo_generic(struct file *file,
struct tcon_link *tlink);
+extern void cifs_oplock_break_generic(struct work_struct *work,
+ oplock_callback_t *oplock_cb);
extern int cifs_posix_open(const char *full_path, struct inode **pinode,
struct super_block *sb, int mode,
unsigned int f_flags, __u32 *poplock, __u16 *pnetfid,
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index e46c2bd..c8a94a4 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -960,7 +960,7 @@ cifs_demultiplex_thread(void *p)
if (mid_entry != NULL) {
if (!mid_entry->multiRsp || mid_entry->multiEnd)
mid_entry->callback(mid_entry);
- } else if (!is_valid_oplock_break((void *)buf, server)) {
+ } else if (!is_valid_oplock_break(buf, server)) {
cERROR(1, "No task to wake, unknown frame received! "
"NumMids %d", atomic_read(&midCount));
cifs_dump_mem("Received Data is: ", buf, buf_size);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 09655f7..a43856a 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -257,6 +257,7 @@ cifs_new_fileinfo(__u16 netfid, struct file *file,
cifs_file->netfid = netfid;
cifs_set_oplock_level(cinode, oplock);
cinode->can_cache_brlcks = cinode->clientCanCacheAll;
+ INIT_WORK(&cifs_file->oplock_break, cifs_oplock_break);
return cifs_file;
}
@@ -280,7 +281,6 @@ cifs_new_fileinfo_generic(struct file *file, struct
tcon_link *tlink)
pCifsFile->invalidHandle = false;
pCifsFile->tlink = cifs_get_tlink(tlink);
mutex_init(&pCifsFile->fh_mutex);
- INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
spin_lock(&cifs_file_list_lock);
list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
@@ -3088,7 +3088,8 @@ int cifs_launder_page(struct page *page)
return rc;
}
-void cifs_oplock_break(struct work_struct *work)
+void cifs_oplock_break_generic(struct work_struct *work,
+ oplock_callback_t *oplock_cb)
{
struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
oplock_break);
@@ -3121,14 +3122,25 @@ void cifs_oplock_break(struct work_struct *work)
* disconnected since oplock already released by the server
*/
if (!cfile->oplock_break_cancelled) {
- rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid,
- current->tgid, 0, 0, 0, 0,
- LOCKING_ANDX_OPLOCK_RELEASE, false,
- cinode->clientCanCacheRead ? 1 : 0);
+ rc = oplock_cb(tlink_tcon(cfile->tlink), cinode, cfile);
cFYI(1, "Oplock release rc = %d", rc);
}
}
+static int
+cifs_oplock_cb(struct cifs_tcon *tcon, struct cifsInodeInfo *cinode,
+ struct cifsFileInfo *cfile)
+{
+ return CIFSSMBLock(0, tcon, cfile->netfid, current->tgid, 0, 0, 0, 0,
+ LOCKING_ANDX_OPLOCK_RELEASE, false,
+ cinode->clientCanCacheRead ? 1 : 0);
+}
+
+void cifs_oplock_break(struct work_struct *work)
+{
+ cifs_oplock_break_generic(work, cifs_oplock_cb);
+}
+
const struct address_space_operations cifs_addr_ops = {
.readpage = cifs_readpage,
.readpages = cifs_readpages,
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index d291463..88bede1 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -29,6 +29,9 @@
#include "smberr.h"
#include "nterr.h"
#include "cifs_unicode.h"
+#ifdef CONFIG_CIFS_SMB2
+#include "smb2proto.h"
+#endif
extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp;
@@ -505,8 +508,9 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int
total_read)
}
bool
-is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
+is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
{
+ struct smb_hdr *buf = (struct smb_hdr *)buffer;
struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
struct list_head *tmp, *tmp1, *tmp2;
struct cifs_ses *ses;
@@ -516,7 +520,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct
TCP_Server_Info *srv)
#ifdef CONFIG_CIFS_SMB2
if (srv->is_smb2)
- return false;
+ return smb2_is_valid_oplock_break(buffer, srv);
#endif
cFYI(1, "Checking for oplock break or dnotify response");
@@ -592,9 +596,10 @@ is_valid_oplock_break(struct smb_hdr *buf, struct
TCP_Server_Info *srv)
cifs_set_oplock_level(pCifsInode,
pSMB->OplockLevel ? OPLOCK_READ : 0);
+ netfile->oplock_break_cancelled = false;
+
queue_work(system_nrt_wq,
&netfile->oplock_break);
- netfile->oplock_break_cancelled = false;
spin_unlock(&cifs_file_list_lock);
spin_unlock(&cifs_tcp_ses_lock);
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 58f9edb..a8cb423 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -178,25 +178,6 @@ const struct address_space_operations
smb2_addr_ops_smallbuf = {
.launder_page = cifs_launder_page,
};
-static void
-smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u8 oplock)
-{
- if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
- cinode->clientCanCacheAll = true;
- cinode->clientCanCacheRead = true;
- cFYI(1, "Exclusive Oplock granted on inode %p",
- &cinode->vfs_inode);
- } else if (oplock == SMB2_OPLOCK_LEVEL_II) {
- cinode->clientCanCacheAll = false;
- cinode->clientCanCacheRead = true;
- cFYI(1, "Level II Oplock granted on inode %p",
- &cinode->vfs_inode);
- } else {
- cinode->clientCanCacheAll = false;
- cinode->clientCanCacheRead = false;
- }
-}
-
struct cifsFileInfo *
smb2_new_fileinfo(__u64 persist_fid, __u64 volatile_fid, struct file *file,
struct tcon_link *tlink, __u8 oplock)
@@ -209,6 +190,7 @@ smb2_new_fileinfo(__u64 persist_fid, __u64 volatile_fid,
struct file *file,
cifs_file->persist_fid = persist_fid;
cifs_file->volatile_fid = volatile_fid;
smb2_set_oplock_level(CIFS_I(file->f_path.dentry->d_inode), oplock);
+ INIT_WORK(&cifs_file->oplock_break, smb2_oplock_break);
return cifs_file;
}
@@ -515,3 +497,22 @@ int smb2_strict_fsync(struct file *file, loff_t start,
loff_t end, int datasync)
return cifs_strict_fsync_generic(file, start, end, datasync,
smb2_fsync_cb);
}
+
+static int
+smb2_oplock_cb(struct cifs_tcon *tcon, struct cifsInodeInfo *cinode,
+ struct cifsFileInfo *cfile)
+{
+ if (tcon->ses->server->smb2_dialect_revision == cpu_to_le16(0x0210))
+ return SMB2_lease_break(0, tlink_tcon(cfile->tlink),
+ cinode->lease_key,
+ smb2_get_lease_state(cinode));
+
+ return SMB2_oplock_break(0, tlink_tcon(cfile->tlink),
+ cfile->persist_fid, cfile->volatile_fid,
+ cinode->clientCanCacheRead ? 1 : 0);
+}
+
+void smb2_oplock_break(struct work_struct *work)
+{
+ cifs_oplock_break_generic(work, smb2_oplock_cb);
+}
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 6f7afdc..6b64cd8 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -151,12 +151,19 @@ checkSMB2(struct smb2_hdr *smb, __u64 mid, unsigned int
length)
if (smb2_rsp_struct_sizes[command] !=
le16_to_cpu(smb2->StructureSize2)) {
- if ((smb->Status == 0) ||
- (le16_to_cpu(smb2->StructureSize2) != 9)) {
+ if (command != SMB2OPLOCK_BREAK && ((smb->Status == 0) ||
+ (le16_to_cpu(smb2->StructureSize2) != 9))) {
/* error packets have 9 byte structure size */
cERROR(1, "Illegal response size %d for command %d",
le16_to_cpu(smb2->StructureSize2), command);
return 1;
+ } else if (command == SMB2OPLOCK_BREAK && (smb->Status == 0)
+ && (le16_to_cpu(smb2->StructureSize2) != 44)
+ && (le16_to_cpu(smb2->StructureSize2) != 36)) {
+ /* special case for SMB2.1 lease break message */
+ cERROR(1, "Illegal response size %d for oplock break",
+ le16_to_cpu(smb2->StructureSize2));
+ return 1;
}
}
@@ -171,6 +178,8 @@ checkSMB2(struct smb2_hdr *smb, __u64 mid, unsigned int
length)
if (4 + len != clc_len) {
cFYI(1, "Calculated size %d length %d mismatch for mid %lld",
clc_len, 4 + len, smb->MessageId);
+ if (clc_len + 20 == len && command == SMB2OPLOCK_BREAK)
+ return 0; /* Windows 7 server returns 24 bytes more */
if (clc_len == 4 + len + 1) /* BB FIXME (fix samba) */
return 0; /* BB workaround Samba 3 bug SessSetup rsp */
return 1;
@@ -345,3 +354,170 @@ calc_size_exit:
cFYI(1, "smb2 len %d", len);
return len;
}
+
+__le32
+smb2_get_lease_state(struct cifsInodeInfo *cinode)
+{
+ if (cinode->clientCanCacheAll)
+ return SMB2_LEASE_WRITE_CACHING;
+ else if (cinode->clientCanCacheRead)
+ return SMB2_LEASE_READ_CACHING;
+ return 0;
+}
+
+void
+smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u8 oplock)
+{
+ if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
+ cinode->clientCanCacheAll = true;
+ cinode->clientCanCacheRead = true;
+ cFYI(1, "Exclusive Oplock granted on inode %p",
+ &cinode->vfs_inode);
+ } else if (oplock == SMB2_OPLOCK_LEVEL_II) {
+ cinode->clientCanCacheAll = false;
+ cinode->clientCanCacheRead = true;
+ cFYI(1, "Level II Oplock granted on inode %p",
+ &cinode->vfs_inode);
+ } else {
+ cinode->clientCanCacheAll = false;
+ cinode->clientCanCacheRead = false;
+ }
+}
+
+__u8 smb2_map_lease_to_oplock(__le32 lease_state)
+{
+ if (lease_state & SMB2_LEASE_WRITE_CACHING) {
+ if (lease_state & SMB2_LEASE_HANDLE_CACHING)
+ return SMB2_OPLOCK_LEVEL_BATCH;
+ else
+ return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+ } else if (lease_state & SMB2_LEASE_READ_CACHING)
+ return SMB2_OPLOCK_LEVEL_II;
+ return 0;
+}
+
+static bool
+smb2_is_valid_lease_break(struct smb2_hdr *buf, struct TCP_Server_Info *srv)
+{
+ struct lease_break *pSMB = (struct lease_break *)buf;
+ struct list_head *tmp, *tmp1, *tmp2;
+ struct cifs_ses *ses;
+ struct cifs_tcon *tcon;
+ struct cifsInodeInfo *cinode;
+ struct cifsFileInfo *cfile;
+
+ cFYI(1, "Checking for lease break");
+
+ /* look up tcon based on tid & uid */
+ spin_lock(&cifs_tcp_ses_lock);
+ list_for_each(tmp, &srv->smb_ses_list) {
+ ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
+ list_for_each(tmp1, &ses->tcon_list) {
+ tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
+
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
+ spin_lock(&cifs_file_list_lock);
+ list_for_each(tmp2, &tcon->openFileList) {
+ cfile = list_entry(tmp2, struct cifsFileInfo,
+ tlist);
+ cinode = CIFS_I(cfile->dentry->d_inode);
+
+ if (memcmp(cinode->lease_key, pSMB->LeaseKey,
+ 16))
+ continue;
+
+ cFYI(1, "lease key match, lease break 0x%d",
+ le32_to_cpu(pSMB->NewLeaseState));
+
+ smb2_set_oplock_level(cinode,
+ smb2_map_lease_to_oplock(pSMB->NewLeaseState));
+
+ if (pSMB->Flags &
+ SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED)
+ cfile->oplock_break_cancelled = false;
+ else
+ cfile->oplock_break_cancelled = true;
+
+ queue_work(system_nrt_wq,
+ &cfile->oplock_break);
+
+ spin_unlock(&cifs_file_list_lock);
+ spin_unlock(&cifs_tcp_ses_lock);
+ return true;
+ }
+ spin_unlock(&cifs_file_list_lock);
+ }
+ }
+ spin_unlock(&cifs_tcp_ses_lock);
+ cFYI(1, "Can not process oplock break for non-existent connection");
+ return false;
+}
+
+bool
+smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
+{
+ struct smb2_hdr *buf = (struct smb2_hdr *)buffer;
+ struct oplock_break *pSMB = (struct oplock_break *)buf;
+ struct list_head *tmp, *tmp1, *tmp2;
+ struct cifs_ses *ses;
+ struct cifs_tcon *tcon;
+ struct cifsInodeInfo *cinode;
+ struct cifsFileInfo *cfile;
+
+ cFYI(1, "Checking for oplock break");
+
+ if (pSMB->hdr.Command != SMB2_OPLOCK_BREAK)
+ return false;
+
+ if (le16_to_cpu(pSMB->StructureSize) !=
+ smb2_rsp_struct_sizes[SMB2OPLOCK_BREAK]) {
+ if (le16_to_cpu(pSMB->StructureSize) == 44)
+ return smb2_is_valid_lease_break(buf, srv);
+ else
+ return false;
+ }
+
+ cFYI(1, "oplock level 0x%d", pSMB->OplockLevel);
+
+ /* look up tcon based on tid & uid */
+ spin_lock(&cifs_tcp_ses_lock);
+ list_for_each(tmp, &srv->smb_ses_list) {
+ ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
+ list_for_each(tmp1, &ses->tcon_list) {
+ tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
+
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
+ spin_lock(&cifs_file_list_lock);
+ list_for_each(tmp2, &tcon->openFileList) {
+ cfile = list_entry(tmp2, struct cifsFileInfo,
+ tlist);
+ if (pSMB->PersistentFid != cfile->persist_fid)
+ continue;
+
+ if (pSMB->VolatileFid != cfile->volatile_fid)
+ continue;
+
+ cFYI(1, "file id match, oplock break");
+ cinode = CIFS_I(cfile->dentry->d_inode);
+
+ smb2_set_oplock_level(cinode,
+ pSMB->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0);
+ cfile->oplock_break_cancelled = false;
+
+ queue_work(system_nrt_wq,
+ &cfile->oplock_break);
+
+ spin_unlock(&cifs_file_list_lock);
+ spin_unlock(&cifs_tcp_ses_lock);
+ return true;
+ }
+ spin_unlock(&cifs_file_list_lock);
+ spin_unlock(&cifs_tcp_ses_lock);
+ cFYI(1, "No matching file for oplock break");
+ return true;
+ }
+ }
+ spin_unlock(&cifs_tcp_ses_lock);
+ cFYI(1, "Can not process oplock break for non-existent connection");
+ return false;
+}
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index bcc3513..25d7ac2 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1088,7 +1088,6 @@ parse_lease_state(struct create_rsp *smb)
{
char *data_offset;
struct create_lease *lc;
- __u8 oplock = 0;
bool found = false;
data_offset = (char *)smb;
@@ -1111,19 +1110,9 @@ parse_lease_state(struct create_rsp *smb)
} while (le32_to_cpu(lc->ccontext.Next) != 0);
if (!found)
- return oplock;
-
- if (le32_to_cpu(lc->lcontext.LeaseState) & SMB2_LEASE_WRITE_CACHING) {
- if (le32_to_cpu(lc->lcontext.LeaseState) &
- SMB2_LEASE_HANDLE_CACHING)
- oplock = SMB2_OPLOCK_LEVEL_BATCH;
- else
- oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
- } else if (le32_to_cpu(lc->lcontext.LeaseState) &
- SMB2_LEASE_READ_CACHING)
- oplock = SMB2_OPLOCK_LEVEL_II;
+ return 0;
- return oplock;
+ return smb2_map_lease_to_oplock(lc->lcontext.LeaseState);
}
int SMB2_open(const int xid, struct cifs_tcon *tcon, __le16 *path,
@@ -1901,12 +1890,6 @@ qfsdev_exit:
return rc;
}
-int SMB2_oplock_break(struct cifs_tcon *ptcon, __u64 netfid)
-{
- /* BB FIXME BB */
- return -EOPNOTSUPP;
-}
-
int SMB2_query_info(const int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid,
FILE_ALL_INFO_SMB2 *pdata)
@@ -2784,3 +2767,72 @@ int SMB2_lock(const int xid, struct cifs_tcon *tcon,
*/
return rc;
}
+
+int
+SMB2_oplock_break(const int xid, struct cifs_tcon *tcon,
+ const u64 persistent_fid, const u64 volatile_fid,
+ __u8 oplock_level)
+{
+ int rc = 0, buf_type, status;
+ struct oplock_break *pSMB2 = NULL;
+ struct kvec iov[1];
+
+ cFYI(1, "SMB2_oplock_break");
+ rc = small_smb2_init(SMB2_OPLOCK_BREAK, tcon, (void **) &pSMB2);
+
+ if (rc)
+ return rc;
+
+ pSMB2->VolatileFid = volatile_fid;
+ pSMB2->PersistentFid = persistent_fid;
+ pSMB2->OplockLevel = oplock_level;
+
+ iov->iov_base = (char *)pSMB2;
+ iov->iov_len = get_rfc1002_length(pSMB2) + 4;
+
+ rc = smb2_sendrcv2(xid, tcon->ses, iov, 1, &buf_type, &status,
+ CIFS_STD_OP | CIFS_LOG_ERROR);
+ /* SMB2 buffer freed by function above */
+
+ if (rc) {
+ cifs_stats_fail_inc(tcon, SMB2OPLOCK_BREAK);
+ cFYI(1, "Send error in Oplock Break = %d", rc);
+ }
+
+ return rc;
+}
+
+int
+SMB2_lease_break(const int xid, struct cifs_tcon *tcon, __u8 *lease_key,
+ const __le32 lease_state)
+{
+ int rc = 0, buf_type, status;
+ struct lease_ack *pSMB2 = NULL;
+ struct kvec iov[1];
+
+ cFYI(1, "SMB2_lease_break");
+ rc = small_smb2_init(SMB2_OPLOCK_BREAK, tcon, (void **) &pSMB2);
+
+ if (rc)
+ return rc;
+
+ pSMB2->StructureSize = cpu_to_le16(36);
+ inc_rfc1001_len(&pSMB2->hdr, 12);
+
+ memcpy(pSMB2->LeaseKey, lease_key, 16);
+ pSMB2->LeaseState = lease_state;
+
+ iov->iov_base = (char *)pSMB2;
+ iov->iov_len = get_rfc1002_length(pSMB2) + 4;
+
+ rc = smb2_sendrcv2(xid, tcon->ses, iov, 1, &buf_type, &status,
+ CIFS_STD_OP | CIFS_LOG_ERROR);
+ /* SMB2 buffer freed by function above */
+
+ if (rc) {
+ cifs_stats_fail_inc(tcon, SMB2OPLOCK_BREAK);
+ cFYI(1, "Send error in Oplock Break = %d", rc);
+ }
+
+ return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 6b8fd2f..3558057 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -741,6 +741,41 @@ struct ioctl_rsp {
__u8 Buffer[1];
} __attribute__((packed));
+struct oplock_break {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 24 */
+ __u8 OplockLevel;
+ __u8 Reserved;
+ __le32 Reserved2;
+ __u64 PersistentFid;
+ __u64 VolatileFid;
+} __attribute__((packed));
+
+#define SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED cpu_to_le32(0x01)
+
+struct lease_break {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 44 */
+ __le16 Reserved;
+ __le32 Flags;
+ __u8 LeaseKey[16];
+ __le32 CurrentLeaseState;
+ __le32 NewLeaseState;
+ __le32 BreakReason;
+ __le32 AccessMaskHint;
+ __le32 ShareMaskHint;
+} __attribute__((packed));
+
+struct lease_ack {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 36 */
+ __le16 Reserved;
+ __le32 Flags;
+ __u8 LeaseKey[16];
+ __le32 LeaseState;
+ __le64 LeaseDuration;
+} __attribute__((packed));
+
/*****************************************************************
* All constants go here
*****************************************************************
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 2408be1..490f922 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -200,7 +200,6 @@ extern int SMB2_QFS_attribute_info(const int xid, struct
cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid);
extern int SMB2_QFS_device_info(const int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid);
-extern int SMB2_oplock_break(struct cifs_tcon *ptcon, __u64 netfid);
extern int SMB2_query_info(const int xid, struct cifs_tcon *tcon,
u64 persistent_file_id, u64 volatile_file_id,
FILE_ALL_INFO_SMB2 *pFindData);
@@ -252,6 +251,11 @@ extern int SMB2_set_ea_info(const int xid, struct
cifs_tcon *tcon,
extern int SMB2_lock(const int xid, struct cifs_tcon *tcon,
const u64 persistent_fid, const u64 volatile_fid,
u64 length, u64 offset, u32 lockFlags, int wait);
+extern int SMB2_oplock_break(const int xid, struct cifs_tcon *tcon,
+ const u64 persistent_fid, const u64 volatile_fid,
+ const __u8 oplock_level);
+extern int SMB2_lease_break(const int xid, struct cifs_tcon *tcon,
+ __u8 *lease_key, const __le32 lease_state);
extern void DeleteMidQEntryComplex(struct mid_q_entry *midEntry);
extern int new_read_req(struct kvec *iov, struct cifs_io_parms *io_parms,
unsigned int remaining_bytes, int request_type);
@@ -262,7 +266,11 @@ extern int smb2_wait_on_complex_mid(struct cifs_ses *ses,
unsigned long timeout,
unsigned long time_to_wait);
extern int smb2_readresp(struct TCP_Server_Info *server, bool cleanup);
-/* extern void smb2_oplock_break(struct work_struct *);
-extern bool is_smb2_oplock_break(struct smb2_hdr *, struct TCP_Server_Info
*);*/
+extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode);
+extern __u8 smb2_map_lease_to_oplock(__le32 lease_state);
+extern void smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u8 oplock);
+extern bool smb2_is_valid_oplock_break(char *buffer,
+ struct TCP_Server_Info *srv);
+extern void smb2_oplock_break(struct work_struct *work);
#endif /* _SMB2PROTO_H */
--
1.7.1
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html