Skip to content

Commit 93b7152

Browse files
shirishpargaonkargregkh
authored andcommitted
cifs: fix oops while traversing open file list (try raspberrypi#4)
commit 2c0c2a0 upstream. 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. Signed-off-by: Shirish Pargaonkar <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Steve French <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent e48fdd4 commit 93b7152

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
@@ -973,10 +973,11 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
973973
struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
974974
bool fsuid_only)
975975
{
976-
struct cifsFileInfo *open_file;
976+
struct cifsFileInfo *open_file, *inv_file = NULL;
977977
struct cifs_sb_info *cifs_sb;
978978
bool any_available = false;
979979
int rc;
980+
unsigned int refind = 0;
980981

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

997998
spin_lock(&cifs_file_list_lock);
998999
refind_writable:
1000+
if (refind > MAX_REOPEN_ATT) {
1001+
spin_unlock(&cifs_file_list_lock);
1002+
return NULL;
1003+
}
9991004
list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
10001005
if (!any_available && open_file->pid != current->tgid)
10011006
continue;
10021007
if (fsuid_only && open_file->uid != current_fsuid())
10031008
continue;
10041009
if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
1005-
cifsFileInfo_get(open_file);
1006-
10071010
if (!open_file->invalidHandle) {
10081011
/* found a good writable file */
1012+
cifsFileInfo_get(open_file);
10091013
spin_unlock(&cifs_file_list_lock);
10101014
return open_file;
1015+
} else {
1016+
if (!inv_file)
1017+
inv_file = open_file;
10111018
}
1012-
1013-
spin_unlock(&cifs_file_list_lock);
1014-
1015-
/* Had to unlock since following call can block */
1016-
rc = cifs_reopen_file(open_file, false);
1017-
if (!rc)
1018-
return open_file;
1019-
1020-
/* if it fails, try another handle if possible */
1021-
cFYI(1, "wp failed on reopen file");
1022-
cifsFileInfo_put(open_file);
1023-
1024-
spin_lock(&cifs_file_list_lock);
1025-
1026-
/* else we simply continue to the next entry. Thus
1027-
we do not loop on reopen errors. If we
1028-
can not reopen the file, for example if we
1029-
reconnected to a server with another client
1030-
racing to delete or lock the file we would not
1031-
make progress if we restarted before the beginning
1032-
of the loop here. */
10331019
}
10341020
}
10351021
/* couldn't find useable FH with same pid, try any available */
10361022
if (!any_available) {
10371023
any_available = true;
10381024
goto refind_writable;
10391025
}
1026+
1027+
if (inv_file) {
1028+
any_available = false;
1029+
cifsFileInfo_get(inv_file);
1030+
}
1031+
10401032
spin_unlock(&cifs_file_list_lock);
1033+
1034+
if (inv_file) {
1035+
rc = cifs_reopen_file(inv_file, false);
1036+
if (!rc)
1037+
return inv_file;
1038+
else {
1039+
spin_lock(&cifs_file_list_lock);
1040+
list_move_tail(&inv_file->flist,
1041+
&cifs_inode->openFileList);
1042+
spin_unlock(&cifs_file_list_lock);
1043+
cifsFileInfo_put(inv_file);
1044+
spin_lock(&cifs_file_list_lock);
1045+
++refind;
1046+
goto refind_writable;
1047+
}
1048+
}
1049+
10411050
return NULL;
10421051
}
10431052

0 commit comments

Comments
 (0)