Commit 78c09634 authored by Rohith Surabattula's avatar Rohith Surabattula Committed by Steve French

Cifs: Fix kernel oops caused by deferred close for files.

Fix regression issue caused by deferred close for files.
Signed-off-by: default avatarRohith Surabattula <rohiths@microsoft.com>
Reviewed-by: default avatarShyam Prasad N <sprasad@microsoft.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 5c1acf3f
...@@ -278,6 +278,8 @@ extern void cifs_del_deferred_close(struct cifsFileInfo *cfile); ...@@ -278,6 +278,8 @@ extern void cifs_del_deferred_close(struct cifsFileInfo *cfile);
extern void cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode); extern void cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode);
extern void cifs_close_all_deferred_files(struct cifs_tcon *cifs_tcon);
extern struct TCP_Server_Info *cifs_get_tcp_session(struct smb3_fs_context *ctx); extern struct TCP_Server_Info *cifs_get_tcp_session(struct smb3_fs_context *ctx);
extern void cifs_put_tcp_session(struct TCP_Server_Info *server, extern void cifs_put_tcp_session(struct TCP_Server_Info *server,
int from_reconnect); int from_reconnect);
......
...@@ -878,6 +878,10 @@ void smb2_deferred_work_close(struct work_struct *work) ...@@ -878,6 +878,10 @@ 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) {
spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
return;
}
cifs_del_deferred_close(cfile); cifs_del_deferred_close(cfile);
cfile->deferred_scheduled = false; cfile->deferred_scheduled = false;
spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock); spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
...@@ -1987,8 +1991,10 @@ cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data, ...@@ -1987,8 +1991,10 @@ cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data,
if (total_written > 0) { if (total_written > 0) {
spin_lock(&d_inode(dentry)->i_lock); spin_lock(&d_inode(dentry)->i_lock);
if (*offset > d_inode(dentry)->i_size) if (*offset > d_inode(dentry)->i_size) {
i_size_write(d_inode(dentry), *offset); i_size_write(d_inode(dentry), *offset);
d_inode(dentry)->i_blocks = (512 - 1 + *offset) >> 9;
}
spin_unlock(&d_inode(dentry)->i_lock); spin_unlock(&d_inode(dentry)->i_lock);
} }
mark_inode_dirty_sync(d_inode(dentry)); mark_inode_dirty_sync(d_inode(dentry));
...@@ -2647,8 +2653,10 @@ static int cifs_write_end(struct file *file, struct address_space *mapping, ...@@ -2647,8 +2653,10 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
if (rc > 0) { if (rc > 0) {
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
if (pos > inode->i_size) if (pos > inode->i_size) {
i_size_write(inode, pos); i_size_write(inode, pos);
inode->i_blocks = (512 - 1 + pos) >> 9;
}
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
...@@ -4864,7 +4872,6 @@ void cifs_oplock_break(struct work_struct *work) ...@@ -4864,7 +4872,6 @@ void cifs_oplock_break(struct work_struct *work)
cinode); cinode);
cifs_dbg(FYI, "Oplock release rc = %d\n", rc); cifs_dbg(FYI, "Oplock release rc = %d\n", rc);
} }
_cifsFileInfo_put(cfile, false /* do not wait for ourself */, false);
/* /*
* 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 set the flag oplock_break_received.
...@@ -4872,11 +4879,12 @@ void cifs_oplock_break(struct work_struct *work) ...@@ -4872,11 +4879,12 @@ void cifs_oplock_break(struct work_struct *work)
*/ */
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) { if (is_deferred && cfile->deferred_scheduled) {
cfile->oplock_break_received = true; cfile->oplock_break_received = true;
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);
_cifsFileInfo_put(cfile, false /* do not wait for ourself */, false);
cifs_done_oplock_break(cinode); cifs_done_oplock_break(cinode);
} }
......
...@@ -1647,7 +1647,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -1647,7 +1647,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
goto unlink_out; goto unlink_out;
} }
cifs_close_deferred_file(CIFS_I(inode)); cifs_close_all_deferred_files(tcon);
if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))) { le64_to_cpu(tcon->fsUnixInfo.Capability))) {
rc = CIFSPOSIXDelFile(xid, tcon, full_path, rc = CIFSPOSIXDelFile(xid, tcon, full_path,
...@@ -2125,6 +2125,7 @@ cifs_rename2(struct user_namespace *mnt_userns, struct inode *source_dir, ...@@ -2125,6 +2125,7 @@ cifs_rename2(struct user_namespace *mnt_userns, struct inode *source_dir,
goto cifs_rename_exit; goto cifs_rename_exit;
} }
cifs_close_all_deferred_files(tcon);
rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry, rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
to_name); to_name);
......
...@@ -734,6 +734,23 @@ cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode) ...@@ -734,6 +734,23 @@ cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode)
} }
} }
void
cifs_close_all_deferred_files(struct cifs_tcon *tcon)
{
struct cifsFileInfo *cfile;
struct cifsInodeInfo *cinode;
struct list_head *tmp;
spin_lock(&tcon->open_file_lock);
list_for_each(tmp, &tcon->openFileList) {
cfile = list_entry(tmp, struct cifsFileInfo, tlist);
cinode = CIFS_I(d_inode(cfile->dentry));
if (delayed_work_pending(&cfile->deferred))
mod_delayed_work(deferredclose_wq, &cfile->deferred, 0);
}
spin_unlock(&tcon->open_file_lock);
}
/* parses DFS refferal V3 structure /* parses DFS refferal V3 structure
* caller is responsible for freeing target_nodes * caller is responsible for freeing target_nodes
* returns: * returns:
......
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