diff --git a/fs/cifs/file.c b/fs/cifs/file.c index dc7175b75c26465fe497db41b0e0f5340b9bf19a..0fbae9a2bcdbcf54491049ee052c149349d2160e 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -4783,12 +4783,19 @@ void cifs_oplock_break(struct work_struct *work) struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, oplock_break); struct inode *inode = d_inode(cfile->dentry); + struct super_block *sb = inode->i_sb; struct cifsInodeInfo *cinode = CIFS_I(inode); struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); struct TCP_Server_Info *server = tcon->ses->server; int rc = 0; bool purge_cache = false; + /* + * Hold a reference to the superblock to prevent it and its inodes from + * being freed while we are accessing cinode. Otherwise, _cifsFileInfo_put() + * may release the last reference to the sb and trigger inode eviction. + */ + cifs_sb_active(sb); wait_on_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS, TASK_UNINTERRUPTIBLE); @@ -4836,6 +4843,7 @@ void cifs_oplock_break(struct work_struct *work) } _cifsFileInfo_put(cfile, false /* do not wait for ourself */, false); cifs_done_oplock_break(cinode); + cifs_sb_deactive(sb); } /*