mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-09 14:43:16 +00:00
Cifs: Fix kernel oops caused by deferred close for files.
Fix regression issue caused by deferred close for files. Signed-off-by: Rohith Surabattula <rohiths@microsoft.com> Reviewed-by: Shyam Prasad N <sprasad@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
5c1acf3fe0
commit
78c09634f7
@ -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)
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
|
|
||||||
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 @@ oplock_break_ack:
|
|||||||
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 @@ oplock_break_ack:
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
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,
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user