Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 326313
b: refs/heads/master
c: 233839b
h: refs/heads/master
i:
  326311: 015e6c1
v: v3
  • Loading branch information
Pavel Shilovsky authored and Steve French committed Sep 25, 2012
1 parent 5c16c0d commit 7ad992e
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 11 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 0822f51426b51bd599b3a7e972b14aacaa045a92
refs/heads/master: 233839b1df65a24c8b67b748fe7b18d86d0ad6d7
12 changes: 12 additions & 0 deletions trunk/fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,7 @@ struct cifs_ses {
__u16 session_flags;
#endif /* CONFIG_CIFS_SMB2 */
};

/* no more than one of the following three session flags may be set */
#define CIFS_SES_NT4 1
#define CIFS_SES_OS2 2
Expand Down Expand Up @@ -821,6 +822,7 @@ struct cifs_tcon {
u64 resource_id; /* server resource id */
struct fscache_cookie *fscache; /* cookie for share */
#endif
struct list_head pending_opens; /* list of incomplete opens */
/* BB add field for back pointer to sb struct(s)? */
};

Expand Down Expand Up @@ -863,6 +865,15 @@ cifs_get_tlink(struct tcon_link *tlink)
/* This function is always expected to succeed */
extern struct cifs_tcon *cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb);

#define CIFS_OPLOCK_NO_CHANGE 0xfe

struct cifs_pending_open {
struct list_head olist;
struct tcon_link *tlink;
__u8 lease_key[16];
__u32 oplock;
};

/*
* This info hangs off the cifsFileInfo structure, pointed to by llist.
* This is used to track byte stream locks on the file
Expand Down Expand Up @@ -903,6 +914,7 @@ struct cifs_fid {
__u64 volatile_fid; /* volatile file id for smb2 */
__u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for smb2 */
#endif
struct cifs_pending_open *pending_open;
};

struct cifs_fid_locks {
Expand Down
7 changes: 7 additions & 0 deletions trunk/fs/cifs/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,13 @@ extern bool cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset,
__u64 length, __u8 type,
struct cifsLockInfo **conf_lock,
bool rw_check);
extern void cifs_add_pending_open(struct cifs_fid *fid,
struct tcon_link *tlink,
struct cifs_pending_open *open);
extern void cifs_add_pending_open_locked(struct cifs_fid *fid,
struct tcon_link *tlink,
struct cifs_pending_open *open);
extern void cifs_del_pending_open(struct cifs_pending_open *open);

#if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
extern void cifs_dfs_release_automount_timer(void);
Expand Down
1 change: 1 addition & 0 deletions trunk/fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -2645,6 +2645,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
tcon->retry = volume_info->retry;
tcon->nocase = volume_info->nocase;
tcon->local_lease = volume_info->local_lease;
INIT_LIST_HEAD(&tcon->pending_opens);

spin_lock(&cifs_tcp_ses_lock);
list_add(&tcon->tcon_list, &ses->tcon_list);
Expand Down
9 changes: 8 additions & 1 deletion trunk/fs/cifs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
struct cifs_tcon *tcon;
struct TCP_Server_Info *server;
struct cifs_fid fid;
struct cifs_pending_open open;
__u32 oplock;
struct cifsFileInfo *file_info;

Expand Down Expand Up @@ -423,23 +424,29 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
if (server->ops->new_lease_key)
server->ops->new_lease_key(&fid);

cifs_add_pending_open(&fid, tlink, &open);

rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
&oplock, &fid, opened);

if (rc)
if (rc) {
cifs_del_pending_open(&open);
goto out;
}

rc = finish_open(file, direntry, generic_file_open, opened);
if (rc) {
if (server->ops->close)
server->ops->close(xid, tcon, &fid);
cifs_del_pending_open(&open);
goto out;
}

file_info = cifs_new_fileinfo(&fid, file, tlink, oplock);
if (file_info == NULL) {
if (server->ops->close)
server->ops->close(xid, tcon, &fid);
cifs_del_pending_open(&open);
rc = -ENOMEM;
}

Expand Down
35 changes: 31 additions & 4 deletions trunk/fs/cifs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
struct cifsInodeInfo *cinode = CIFS_I(inode);
struct cifsFileInfo *cfile;
struct cifs_fid_locks *fdlocks;
struct cifs_tcon *tcon = tlink_tcon(tlink);

cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
if (cfile == NULL)
Expand Down Expand Up @@ -274,10 +275,15 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
cfile->tlink = cifs_get_tlink(tlink);
INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
mutex_init(&cfile->fh_mutex);
tlink_tcon(tlink)->ses->server->ops->set_fid(cfile, fid, oplock);

spin_lock(&cifs_file_list_lock);
list_add(&cfile->tlist, &(tlink_tcon(tlink)->openFileList));
if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE)
oplock = fid->pending_open->oplock;
list_del(&fid->pending_open->olist);

tlink_tcon(tlink)->ses->server->ops->set_fid(cfile, fid, oplock);

list_add(&cfile->tlist, &tcon->openFileList);
/* if readable file instance put first in list*/
if (file->f_mode & FMODE_READ)
list_add(&cfile->flist, &cinode->openFileList);
Expand Down Expand Up @@ -307,16 +313,25 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
{
struct inode *inode = cifs_file->dentry->d_inode;
struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink);
struct TCP_Server_Info *server = tcon->ses->server;
struct cifsInodeInfo *cifsi = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsLockInfo *li, *tmp;
struct cifs_fid fid;
struct cifs_pending_open open;

spin_lock(&cifs_file_list_lock);
if (--cifs_file->count > 0) {
spin_unlock(&cifs_file_list_lock);
return;
}

if (server->ops->get_lease_key)
server->ops->get_lease_key(inode, &fid);

/* store open in pending opens to make sure we don't miss lease break */
cifs_add_pending_open_locked(&fid, cifs_file->tlink, &open);

/* remove it from the lists */
list_del(&cifs_file->flist);
list_del(&cifs_file->tlist);
Expand Down Expand Up @@ -348,6 +363,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
free_xid(xid);
}

cifs_del_pending_open(&open);

/*
* Delete any outstanding lock records. We'll lose them when the file
* is closed anyway.
Expand All @@ -368,6 +385,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
}

int cifs_open(struct inode *inode, struct file *file)

{
int rc = -EACCES;
unsigned int xid;
Expand All @@ -380,6 +398,7 @@ int cifs_open(struct inode *inode, struct file *file)
char *full_path = NULL;
bool posix_open_ok = false;
struct cifs_fid fid;
struct cifs_pending_open open;

xid = get_xid();

Expand All @@ -401,7 +420,7 @@ int cifs_open(struct inode *inode, struct file *file)
cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
inode, file->f_flags, full_path);

if (tcon->ses->server->oplocks)
if (server->oplocks)
oplock = REQ_OPLOCK;
else
oplock = 0;
Expand Down Expand Up @@ -434,20 +453,28 @@ int cifs_open(struct inode *inode, struct file *file)
*/
}

if (server->ops->get_lease_key)
server->ops->get_lease_key(inode, &fid);

cifs_add_pending_open(&fid, tlink, &open);

if (!posix_open_ok) {
if (server->ops->get_lease_key)
server->ops->get_lease_key(inode, &fid);

rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
file->f_flags, &oplock, &fid, xid);
if (rc)
if (rc) {
cifs_del_pending_open(&open);
goto out;
}
}

cfile = cifs_new_fileinfo(&fid, file, tlink, oplock);
if (cfile == NULL) {
if (server->ops->close)
server->ops->close(xid, tcon, &fid);
cifs_del_pending_open(&open);
rc = -ENOMEM;
goto out;
}
Expand Down
30 changes: 30 additions & 0 deletions trunk/fs/cifs/misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -579,3 +579,33 @@ backup_cred(struct cifs_sb_info *cifs_sb)

return false;
}

void
cifs_del_pending_open(struct cifs_pending_open *open)
{
spin_lock(&cifs_file_list_lock);
list_del(&open->olist);
spin_unlock(&cifs_file_list_lock);
}

void
cifs_add_pending_open_locked(struct cifs_fid *fid, struct tcon_link *tlink,
struct cifs_pending_open *open)
{
#ifdef CONFIG_CIFS_SMB2
memcpy(open->lease_key, fid->lease_key, SMB2_LEASE_KEY_SIZE);
#endif
open->oplock = CIFS_OPLOCK_NO_CHANGE;
open->tlink = tlink;
fid->pending_open = open;
list_add_tail(&open->olist, &tlink_tcon(tlink)->pending_opens);
}

void
cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink,
struct cifs_pending_open *open)
{
spin_lock(&cifs_file_list_lock);
cifs_add_pending_open_locked(fid, tlink, open);
spin_unlock(&cifs_file_list_lock);
}
74 changes: 69 additions & 5 deletions trunk/fs/cifs/smb2misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,27 @@ __u8 smb2_map_lease_to_oplock(__le32 lease_state)
return 0;
}

struct smb2_lease_break_work {
struct work_struct lease_break;
struct tcon_link *tlink;
__u8 lease_key[16];
__le32 lease_state;
};

static void
cifs_ses_oplock_break(struct work_struct *work)
{
struct smb2_lease_break_work *lw = container_of(work,
struct smb2_lease_break_work, lease_break);
int rc;

rc = SMB2_lease_break(0, tlink_tcon(lw->tlink), lw->lease_key,
lw->lease_state);
cFYI(1, "Lease release rc %d", rc);
cifs_put_tlink(lw->tlink);
kfree(lw);
}

static bool
smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server)
{
Expand All @@ -398,35 +419,49 @@ smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server)
struct cifs_tcon *tcon;
struct cifsInodeInfo *cinode;
struct cifsFileInfo *cfile;
struct cifs_pending_open *open;
struct smb2_lease_break_work *lw;
bool found;
int ack_req = rsp->Flags & SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED;

lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL);
if (!lw) {
cERROR(1, "Memory allocation failed during lease break check");
return false;
}

INIT_WORK(&lw->lease_break, cifs_ses_oplock_break);
lw->lease_state = rsp->NewLeaseState;

cFYI(1, "Checking for lease break");

/* look up tcon based on tid & uid */
spin_lock(&cifs_tcp_ses_lock);
list_for_each(tmp, &server->smb_ses_list) {
ses = list_entry(tmp, struct cifs_ses, smb_ses_list);

spin_lock(&cifs_file_list_lock);
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);
tlist);
cinode = CIFS_I(cfile->dentry->d_inode);

if (memcmp(cinode->lease_key, rsp->LeaseKey,
SMB2_LEASE_KEY_SIZE))
continue;

cFYI(1, "found in the open list");
cFYI(1, "lease key match, lease break 0x%d",
le32_to_cpu(rsp->NewLeaseState));

smb2_set_oplock_level(cinode,
smb2_map_lease_to_oplock(rsp->NewLeaseState));

if (rsp->Flags &
SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED)
if (ack_req)
cfile->oplock_break_cancelled = false;
else
cfile->oplock_break_cancelled = true;
Expand All @@ -437,10 +472,39 @@ smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server)
spin_unlock(&cifs_tcp_ses_lock);
return true;
}
spin_unlock(&cifs_file_list_lock);

found = false;
list_for_each_entry(open, &tcon->pending_opens, olist) {
if (memcmp(open->lease_key, rsp->LeaseKey,
SMB2_LEASE_KEY_SIZE))
continue;

if (!found && ack_req) {
found = true;
memcpy(lw->lease_key, open->lease_key,
SMB2_LEASE_KEY_SIZE);
lw->tlink = cifs_get_tlink(open->tlink);
queue_work(cifsiod_wq,
&lw->lease_break);
}

cFYI(1, "found in the pending open list");
cFYI(1, "lease key match, lease break 0x%d",
le32_to_cpu(rsp->NewLeaseState));

open->oplock =
smb2_map_lease_to_oplock(rsp->NewLeaseState);
}
if (found) {
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);
kfree(lw);
cFYI(1, "Can not process lease break - no lease matched");
return false;
}
Expand Down

0 comments on commit 7ad992e

Please sign in to comment.