Skip to content

Commit

Permalink
smb3: add missing worker function for SMB3 change notify
Browse files Browse the repository at this point in the history
SMB3 change notify is important to allow applications to wait
on directory change events of different types (e.g. adding
and deleting files from others systems). Add worker functions
for this.

Acked-by: Aurelien Aptel <[email protected]>
Signed-off-by: Steve French <[email protected]>
  • Loading branch information
Steve French committed Sep 16, 2019
1 parent 8eecd1c commit c349818
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 0 deletions.
85 changes: 85 additions & 0 deletions fs/cifs/smb2pdu.c
Original file line number Diff line number Diff line change
Expand Up @@ -3175,6 +3175,91 @@ SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
(void **)&uniqueid, NULL);
}

/*
* CHANGE_NOTIFY Request is sent to get notifications on changes to a directory
* See MS-SMB2 2.2.35 and 2.2.36
*/

int
SMB2_notify_init(const unsigned int xid, struct smb_rqst *rqst,
struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid,
u32 completion_filter, bool watch_tree)
{
struct smb2_change_notify_req *req;
struct kvec *iov = rqst->rq_iov;
unsigned int total_len;
int rc;

rc = smb2_plain_req_init(SMB2_CHANGE_NOTIFY, tcon, (void **) &req, &total_len);
if (rc)
return rc;

req->PersistentFileId = persistent_fid;
req->VolatileFileId = volatile_fid;
req->OutputBufferLength = SMB2_MAX_BUFFER_SIZE - MAX_SMB2_HDR_SIZE;
req->CompletionFilter = cpu_to_le32(completion_filter);
if (watch_tree)
req->Flags = cpu_to_le16(SMB2_WATCH_TREE);
else
req->Flags = 0;

iov[0].iov_base = (char *)req;
iov[0].iov_len = total_len;

return 0;
}

int
SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, bool watch_tree,
u32 completion_filter)
{
struct cifs_ses *ses = tcon->ses;
struct smb_rqst rqst;
struct kvec iov[1];
struct kvec rsp_iov = {NULL, 0};
int resp_buftype = CIFS_NO_BUFFER;
int flags = 0;
int rc = 0;

cifs_dbg(FYI, "change notify\n");
if (!ses || !(ses->server))
return -EIO;

if (smb3_encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ;

memset(&rqst, 0, sizeof(struct smb_rqst));
memset(&iov, 0, sizeof(iov));
rqst.rq_iov = iov;
rqst.rq_nvec = 1;

rc = SMB2_notify_init(xid, &rqst, tcon, persistent_fid, volatile_fid,
completion_filter, watch_tree);
if (rc)
goto cnotify_exit;

trace_smb3_notify_enter(xid, persistent_fid, tcon->tid, ses->Suid,
(u8)watch_tree, completion_filter);
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);

if (rc != 0) {
cifs_stats_fail_inc(tcon, SMB2_CHANGE_NOTIFY_HE);
trace_smb3_notify_err(xid, persistent_fid, tcon->tid, ses->Suid,
(u8)watch_tree, completion_filter, rc);
} else
trace_smb3_notify_done(xid, persistent_fid, tcon->tid,
ses->Suid, (u8)watch_tree, completion_filter);

cnotify_exit:
if (rqst.rq_iov)
cifs_small_buf_release(rqst.rq_iov[0].iov_base); /* request */
free_rsp_buf(resp_buftype, rsp_iov.iov_base);
return rc;
}



/*
* This is a no-op for now. We're not really interested in the reply, but
* rather in the fact that the server sent one and that server->lstrp
Expand Down
3 changes: 3 additions & 0 deletions fs/cifs/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ DEFINE_EVENT(smb3_inf_enter_class, smb3_##name, \

DEFINE_SMB3_INF_ENTER_EVENT(query_info_enter);
DEFINE_SMB3_INF_ENTER_EVENT(query_info_done);
DEFINE_SMB3_INF_ENTER_EVENT(notify_enter);
DEFINE_SMB3_INF_ENTER_EVENT(notify_done);

DECLARE_EVENT_CLASS(smb3_inf_err_class,
TP_PROTO(unsigned int xid,
Expand Down Expand Up @@ -281,6 +283,7 @@ DEFINE_EVENT(smb3_inf_err_class, smb3_##name, \

DEFINE_SMB3_INF_ERR_EVENT(query_info_err);
DEFINE_SMB3_INF_ERR_EVENT(set_info_err);
DEFINE_SMB3_INF_ERR_EVENT(notify_err);
DEFINE_SMB3_INF_ERR_EVENT(fsctl_err);

DECLARE_EVENT_CLASS(smb3_inf_compound_enter_class,
Expand Down

0 comments on commit c349818

Please sign in to comment.