Skip to content

Commit 78c0963

Browse files
rohiths-msftsmfrench
authored andcommitted
Cifs: Fix kernel oops caused by deferred close for files.
Fix regression issue caused by deferred close for files. Signed-off-by: Rohith Surabattula <[email protected]> Reviewed-by: Shyam Prasad N <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 5c1acf3 commit 78c0963

File tree

4 files changed

+33
-5
lines changed

4 files changed

+33
-5
lines changed

fs/cifs/cifsproto.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@ extern void cifs_del_deferred_close(struct cifsFileInfo *cfile);
278278

279279
extern void cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode);
280280

281+
extern void cifs_close_all_deferred_files(struct cifs_tcon *cifs_tcon);
282+
281283
extern struct TCP_Server_Info *cifs_get_tcp_session(struct smb3_fs_context *ctx);
282284
extern void cifs_put_tcp_session(struct TCP_Server_Info *server,
283285
int from_reconnect);

fs/cifs/file.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,10 @@ void smb2_deferred_work_close(struct work_struct *work)
878878
struct cifsFileInfo, deferred.work);
879879

880880
spin_lock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
881+
if (!cfile->deferred_scheduled) {
882+
spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
883+
return;
884+
}
881885
cifs_del_deferred_close(cfile);
882886
cfile->deferred_scheduled = false;
883887
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,
19871991

19881992
if (total_written > 0) {
19891993
spin_lock(&d_inode(dentry)->i_lock);
1990-
if (*offset > d_inode(dentry)->i_size)
1994+
if (*offset > d_inode(dentry)->i_size) {
19911995
i_size_write(d_inode(dentry), *offset);
1996+
d_inode(dentry)->i_blocks = (512 - 1 + *offset) >> 9;
1997+
}
19921998
spin_unlock(&d_inode(dentry)->i_lock);
19931999
}
19942000
mark_inode_dirty_sync(d_inode(dentry));
@@ -2647,8 +2653,10 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
26472653

26482654
if (rc > 0) {
26492655
spin_lock(&inode->i_lock);
2650-
if (pos > inode->i_size)
2656+
if (pos > inode->i_size) {
26512657
i_size_write(inode, pos);
2658+
inode->i_blocks = (512 - 1 + pos) >> 9;
2659+
}
26522660
spin_unlock(&inode->i_lock);
26532661
}
26542662

@@ -4864,19 +4872,19 @@ void cifs_oplock_break(struct work_struct *work)
48644872
cinode);
48654873
cifs_dbg(FYI, "Oplock release rc = %d\n", rc);
48664874
}
4867-
_cifsFileInfo_put(cfile, false /* do not wait for ourself */, false);
48684875
/*
48694876
* When oplock break is received and there are no active
48704877
* file handles but cached, then set the flag oplock_break_received.
48714878
* So, new open will not use cached handle.
48724879
*/
48734880
spin_lock(&CIFS_I(inode)->deferred_lock);
48744881
is_deferred = cifs_is_deferred_close(cfile, &dclose);
4875-
if (is_deferred) {
4882+
if (is_deferred && cfile->deferred_scheduled) {
48764883
cfile->oplock_break_received = true;
48774884
mod_delayed_work(deferredclose_wq, &cfile->deferred, 0);
48784885
}
48794886
spin_unlock(&CIFS_I(inode)->deferred_lock);
4887+
_cifsFileInfo_put(cfile, false /* do not wait for ourself */, false);
48804888
cifs_done_oplock_break(cinode);
48814889
}
48824890

fs/cifs/inode.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1647,7 +1647,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
16471647
goto unlink_out;
16481648
}
16491649

1650-
cifs_close_deferred_file(CIFS_I(inode));
1650+
cifs_close_all_deferred_files(tcon);
16511651
if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
16521652
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
16531653
rc = CIFSPOSIXDelFile(xid, tcon, full_path,
@@ -2125,6 +2125,7 @@ cifs_rename2(struct user_namespace *mnt_userns, struct inode *source_dir,
21252125
goto cifs_rename_exit;
21262126
}
21272127

2128+
cifs_close_all_deferred_files(tcon);
21282129
rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
21292130
to_name);
21302131

fs/cifs/misc.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,23 @@ cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode)
734734
}
735735
}
736736

737+
void
738+
cifs_close_all_deferred_files(struct cifs_tcon *tcon)
739+
{
740+
struct cifsFileInfo *cfile;
741+
struct cifsInodeInfo *cinode;
742+
struct list_head *tmp;
743+
744+
spin_lock(&tcon->open_file_lock);
745+
list_for_each(tmp, &tcon->openFileList) {
746+
cfile = list_entry(tmp, struct cifsFileInfo, tlist);
747+
cinode = CIFS_I(d_inode(cfile->dentry));
748+
if (delayed_work_pending(&cfile->deferred))
749+
mod_delayed_work(deferredclose_wq, &cfile->deferred, 0);
750+
}
751+
spin_unlock(&tcon->open_file_lock);
752+
}
753+
737754
/* parses DFS refferal V3 structure
738755
* caller is responsible for freeing target_nodes
739756
* returns:

0 commit comments

Comments
 (0)