Skip to content

Commit 2c0c2a0

Browse files
shirishpargaonkarpiastry
authored andcommitted
cifs: fix oops while traversing open file list (try #4)
While traversing the linked list of open file handles, if the identfied file handle is invalid, a reopen is attempted and if it fails, we resume traversing where we stopped and cifs can oops while accessing invalid next element, for list might have changed. So mark the invalid file handle and attempt reopen if no valid file handle is found in rest of the list. If reopen fails, move the invalid file handle to the end of the list and start traversing the list again from the begining. Repeat this four times before giving up and returning an error if file reopen keeps failing. Cc: <[email protected]> Signed-off-by: Shirish Pargaonkar <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent ea4b574 commit 2c0c2a0

File tree

2 files changed

+34
-24
lines changed

2 files changed

+34
-24
lines changed

fs/cifs/cifsglob.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343

4444
#define CIFS_MIN_RCV_POOL 4
4545

46+
#define MAX_REOPEN_ATT 5 /* these many maximum attempts to reopen a file */
4647
/*
4748
* default attribute cache timeout (jiffies)
4849
*/

fs/cifs/file.c

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,10 +1565,11 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
15651565
struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
15661566
bool fsuid_only)
15671567
{
1568-
struct cifsFileInfo *open_file;
1568+
struct cifsFileInfo *open_file, *inv_file = NULL;
15691569
struct cifs_sb_info *cifs_sb;
15701570
bool any_available = false;
15711571
int rc;
1572+
unsigned int refind = 0;
15721573

15731574
/* Having a null inode here (because mapping->host was set to zero by
15741575
the VFS or MM) should not happen but we had reports of on oops (due to
@@ -1588,48 +1589,56 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
15881589

15891590
spin_lock(&cifs_file_list_lock);
15901591
refind_writable:
1592+
if (refind > MAX_REOPEN_ATT) {
1593+
spin_unlock(&cifs_file_list_lock);
1594+
return NULL;
1595+
}
15911596
list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
15921597
if (!any_available && open_file->pid != current->tgid)
15931598
continue;
15941599
if (fsuid_only && open_file->uid != current_fsuid())
15951600
continue;
15961601
if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
1597-
cifsFileInfo_get(open_file);
1598-
15991602
if (!open_file->invalidHandle) {
16001603
/* found a good writable file */
1604+
cifsFileInfo_get(open_file);
16011605
spin_unlock(&cifs_file_list_lock);
16021606
return open_file;
1607+
} else {
1608+
if (!inv_file)
1609+
inv_file = open_file;
16031610
}
1604-
1605-
spin_unlock(&cifs_file_list_lock);
1606-
1607-
/* Had to unlock since following call can block */
1608-
rc = cifs_reopen_file(open_file, false);
1609-
if (!rc)
1610-
return open_file;
1611-
1612-
/* if it fails, try another handle if possible */
1613-
cFYI(1, "wp failed on reopen file");
1614-
cifsFileInfo_put(open_file);
1615-
1616-
spin_lock(&cifs_file_list_lock);
1617-
1618-
/* else we simply continue to the next entry. Thus
1619-
we do not loop on reopen errors. If we
1620-
can not reopen the file, for example if we
1621-
reconnected to a server with another client
1622-
racing to delete or lock the file we would not
1623-
make progress if we restarted before the beginning
1624-
of the loop here. */
16251611
}
16261612
}
16271613
/* couldn't find useable FH with same pid, try any available */
16281614
if (!any_available) {
16291615
any_available = true;
16301616
goto refind_writable;
16311617
}
1618+
1619+
if (inv_file) {
1620+
any_available = false;
1621+
cifsFileInfo_get(inv_file);
1622+
}
1623+
16321624
spin_unlock(&cifs_file_list_lock);
1625+
1626+
if (inv_file) {
1627+
rc = cifs_reopen_file(inv_file, false);
1628+
if (!rc)
1629+
return inv_file;
1630+
else {
1631+
spin_lock(&cifs_file_list_lock);
1632+
list_move_tail(&inv_file->flist,
1633+
&cifs_inode->openFileList);
1634+
spin_unlock(&cifs_file_list_lock);
1635+
cifsFileInfo_put(inv_file);
1636+
spin_lock(&cifs_file_list_lock);
1637+
++refind;
1638+
goto refind_writable;
1639+
}
1640+
}
1641+
16331642
return NULL;
16341643
}
16351644

0 commit comments

Comments
 (0)