Commit 860b69a9 authored by Rohith Surabattula's avatar Rohith Surabattula Committed by Steve French

Fix kernel oops when CONFIG_DEBUG_ATOMIC_SLEEP is enabled.

Removed oplock_break_received flag which was added to achieve
synchronization between oplock handler and open handler by earlier commit.

It is not needed because there is an existing lock open_file_lock to achieve
the same. find_readable_file takes open_file_lock and then traverses the
openFileList. Similarly, cifs_oplock_break while closing the deferred
handle (i.e cifsFileInfo_put) takes open_file_lock and then sends close
to the server.

Added comments for better readability.
Signed-off-by: default avatarRohith Surabattula <rohiths@microsoft.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent e83aa352
...@@ -133,7 +133,7 @@ struct workqueue_struct *cifsiod_wq; ...@@ -133,7 +133,7 @@ struct workqueue_struct *cifsiod_wq;
struct workqueue_struct *decrypt_wq; struct workqueue_struct *decrypt_wq;
struct workqueue_struct *fileinfo_put_wq; struct workqueue_struct *fileinfo_put_wq;
struct workqueue_struct *cifsoplockd_wq; struct workqueue_struct *cifsoplockd_wq;
struct workqueue_struct *deferredclose_wq; struct workqueue_struct *deferredclose_wq;
__u32 cifs_lock_secret; __u32 cifs_lock_secret;
/* /*
......
...@@ -1257,8 +1257,7 @@ struct cifsFileInfo { ...@@ -1257,8 +1257,7 @@ struct cifsFileInfo {
struct work_struct oplock_break; /* work for oplock breaks */ struct work_struct oplock_break; /* work for oplock breaks */
struct work_struct put; /* work for the final part of _put */ struct work_struct put; /* work for the final part of _put */
struct delayed_work deferred; struct delayed_work deferred;
bool oplock_break_received; /* Flag to indicate oplock break */ bool deferred_close_scheduled; /* Flag to indicate close is scheduled */
bool deferred_scheduled;
}; };
struct cifs_io_parms { struct cifs_io_parms {
......
...@@ -323,8 +323,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, ...@@ -323,8 +323,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
cfile->dentry = dget(dentry); cfile->dentry = dget(dentry);
cfile->f_flags = file->f_flags; cfile->f_flags = file->f_flags;
cfile->invalidHandle = false; cfile->invalidHandle = false;
cfile->oplock_break_received = false; cfile->deferred_close_scheduled = false;
cfile->deferred_scheduled = false;
cfile->tlink = cifs_get_tlink(tlink); cfile->tlink = cifs_get_tlink(tlink);
INIT_WORK(&cfile->oplock_break, cifs_oplock_break); INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
INIT_WORK(&cfile->put, cifsFileInfo_put_work); INIT_WORK(&cfile->put, cifsFileInfo_put_work);
...@@ -574,21 +573,18 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -574,21 +573,18 @@ int cifs_open(struct inode *inode, struct file *file)
file->f_op = &cifs_file_direct_ops; file->f_op = &cifs_file_direct_ops;
} }
spin_lock(&CIFS_I(inode)->deferred_lock);
/* Get the cached handle as SMB2 close is deferred */ /* Get the cached handle as SMB2 close is deferred */
rc = cifs_get_readable_path(tcon, full_path, &cfile); rc = cifs_get_readable_path(tcon, full_path, &cfile);
if (rc == 0) { if (rc == 0) {
if (file->f_flags == cfile->f_flags) { if (file->f_flags == cfile->f_flags) {
file->private_data = cfile; file->private_data = cfile;
spin_lock(&CIFS_I(inode)->deferred_lock);
cifs_del_deferred_close(cfile); cifs_del_deferred_close(cfile);
spin_unlock(&CIFS_I(inode)->deferred_lock); spin_unlock(&CIFS_I(inode)->deferred_lock);
goto out; goto out;
} else { } else {
spin_unlock(&CIFS_I(inode)->deferred_lock);
_cifsFileInfo_put(cfile, true, false); _cifsFileInfo_put(cfile, true, false);
} }
} else {
spin_unlock(&CIFS_I(inode)->deferred_lock);
} }
if (server->oplocks) if (server->oplocks)
...@@ -878,12 +874,12 @@ void smb2_deferred_work_close(struct work_struct *work) ...@@ -878,12 +874,12 @@ void smb2_deferred_work_close(struct work_struct *work)
struct cifsFileInfo, deferred.work); struct cifsFileInfo, deferred.work);
spin_lock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock); spin_lock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
if (!cfile->deferred_scheduled) { if (!cfile->deferred_close_scheduled) {
spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock); spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
return; return;
} }
cifs_del_deferred_close(cfile); cifs_del_deferred_close(cfile);
cfile->deferred_scheduled = false; cfile->deferred_close_scheduled = false;
spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock); spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
_cifsFileInfo_put(cfile, true, false); _cifsFileInfo_put(cfile, true, false);
} }
...@@ -905,14 +901,15 @@ int cifs_close(struct inode *inode, struct file *file) ...@@ -905,14 +901,15 @@ int cifs_close(struct inode *inode, struct file *file)
inode->i_ctime = inode->i_mtime = current_time(inode); inode->i_ctime = inode->i_mtime = current_time(inode);
spin_lock(&cinode->deferred_lock); spin_lock(&cinode->deferred_lock);
cifs_add_deferred_close(cfile, dclose); cifs_add_deferred_close(cfile, dclose);
if (cfile->deferred_scheduled) { if (cfile->deferred_close_scheduled &&
delayed_work_pending(&cfile->deferred)) {
mod_delayed_work(deferredclose_wq, mod_delayed_work(deferredclose_wq,
&cfile->deferred, cifs_sb->ctx->acregmax); &cfile->deferred, cifs_sb->ctx->acregmax);
} else { } else {
/* Deferred close for files */ /* Deferred close for files */
queue_delayed_work(deferredclose_wq, queue_delayed_work(deferredclose_wq,
&cfile->deferred, cifs_sb->ctx->acregmax); &cfile->deferred, cifs_sb->ctx->acregmax);
cfile->deferred_scheduled = true; cfile->deferred_close_scheduled = true;
spin_unlock(&cinode->deferred_lock); spin_unlock(&cinode->deferred_lock);
return 0; return 0;
} }
...@@ -2020,8 +2017,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, ...@@ -2020,8 +2017,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
if (fsuid_only && !uid_eq(open_file->uid, current_fsuid())) if (fsuid_only && !uid_eq(open_file->uid, current_fsuid()))
continue; continue;
if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) { if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) {
if ((!open_file->invalidHandle) && if ((!open_file->invalidHandle)) {
(!open_file->oplock_break_received)) {
/* found a good file */ /* found a good file */
/* lock it so it will not be closed on us */ /* lock it so it will not be closed on us */
cifsFileInfo_get(open_file); cifsFileInfo_get(open_file);
...@@ -4874,13 +4870,14 @@ void cifs_oplock_break(struct work_struct *work) ...@@ -4874,13 +4870,14 @@ void cifs_oplock_break(struct work_struct *work)
} }
/* /*
* When oplock break is received and there are no active * When oplock break is received and there are no active
* file handles but cached, then set the flag oplock_break_received. * file handles but cached, then schedule deferred close immediately.
* So, new open will not use cached handle. * So, new open will not use cached handle.
*/ */
spin_lock(&CIFS_I(inode)->deferred_lock); spin_lock(&CIFS_I(inode)->deferred_lock);
is_deferred = cifs_is_deferred_close(cfile, &dclose); is_deferred = cifs_is_deferred_close(cfile, &dclose);
if (is_deferred && cfile->deferred_scheduled) { if (is_deferred &&
cfile->oplock_break_received = true; cfile->deferred_close_scheduled &&
delayed_work_pending(&cfile->deferred)) {
mod_delayed_work(deferredclose_wq, &cfile->deferred, 0); mod_delayed_work(deferredclose_wq, &cfile->deferred, 0);
} }
spin_unlock(&CIFS_I(inode)->deferred_lock); spin_unlock(&CIFS_I(inode)->deferred_lock);
......
...@@ -672,6 +672,9 @@ cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink, ...@@ -672,6 +672,9 @@ cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink,
spin_unlock(&tlink_tcon(open->tlink)->open_file_lock); spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
} }
/*
* Critical section which runs after acquiring deferred_lock.
*/
bool bool
cifs_is_deferred_close(struct cifsFileInfo *cfile, struct cifs_deferred_close **pdclose) cifs_is_deferred_close(struct cifsFileInfo *cfile, struct cifs_deferred_close **pdclose)
{ {
...@@ -688,6 +691,9 @@ cifs_is_deferred_close(struct cifsFileInfo *cfile, struct cifs_deferred_close ** ...@@ -688,6 +691,9 @@ cifs_is_deferred_close(struct cifsFileInfo *cfile, struct cifs_deferred_close **
return false; return false;
} }
/*
* Critical section which runs after acquiring deferred_lock.
*/
void void
cifs_add_deferred_close(struct cifsFileInfo *cfile, struct cifs_deferred_close *dclose) cifs_add_deferred_close(struct cifsFileInfo *cfile, struct cifs_deferred_close *dclose)
{ {
...@@ -707,6 +713,9 @@ cifs_add_deferred_close(struct cifsFileInfo *cfile, struct cifs_deferred_close * ...@@ -707,6 +713,9 @@ cifs_add_deferred_close(struct cifsFileInfo *cfile, struct cifs_deferred_close *
list_add_tail(&dclose->dlist, &CIFS_I(d_inode(cfile->dentry))->deferred_closes); list_add_tail(&dclose->dlist, &CIFS_I(d_inode(cfile->dentry))->deferred_closes);
} }
/*
* Critical section which runs after acquiring deferred_lock.
*/
void void
cifs_del_deferred_close(struct cifsFileInfo *cfile) cifs_del_deferred_close(struct cifsFileInfo *cfile)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment