CIFS: Fix fast lease break after open problem

Now we walk though cifsFileInfo's list for every incoming lease
break and look for an equivalent there. That approach misses lease
breaks that come just after an open response - we don't have time
to populate new cifsFileInfo structure to the list. Fix this by
adding new list of pending opens and look for a lease there if we
didn't find it in the list of cifsFileInfo structures.

Signed-off-by: Pavel Shilovsky <pshilovsky@etersoft.ru>
Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
Pavel Shilovsky
2012-09-19 06:22:45 -07:00
committed by Steve French
父節點 0822f51426
當前提交 233839b1df
共有 7 個文件被更改,包括 158 次插入10 次删除

查看文件

@@ -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)
@@ -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);
@@ -307,9 +313,12 @@ 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) {
@@ -317,6 +326,12 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
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);
@@ -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.
@@ -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;
@@ -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();
@@ -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;
@@ -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;
}