summaryrefslogtreecommitdiffstats
path: root/fs/cifs/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r--fs/cifs/file.c35
1 files changed, 31 insertions, 4 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index e93e3d2..88e9c74 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -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;
}
OpenPOWER on IntegriCloud