diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/cifsglob.h | 1 | ||||
-rw-r--r-- | fs/cifs/file.c | 57 |
2 files changed, 34 insertions, 24 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 6255fa812c7..7cb9dd22531 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -43,6 +43,7 @@ | |||
43 | 43 | ||
44 | #define CIFS_MIN_RCV_POOL 4 | 44 | #define CIFS_MIN_RCV_POOL 4 |
45 | 45 | ||
46 | #define MAX_REOPEN_ATT 5 /* these many maximum attempts to reopen a file */ | ||
46 | /* | 47 | /* |
47 | * default attribute cache timeout (jiffies) | 48 | * default attribute cache timeout (jiffies) |
48 | */ | 49 | */ |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index a9b4a24f2a1..9040cb0695c 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -973,10 +973,11 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, | |||
973 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, | 973 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, |
974 | bool fsuid_only) | 974 | bool fsuid_only) |
975 | { | 975 | { |
976 | struct cifsFileInfo *open_file; | 976 | struct cifsFileInfo *open_file, *inv_file = NULL; |
977 | struct cifs_sb_info *cifs_sb; | 977 | struct cifs_sb_info *cifs_sb; |
978 | bool any_available = false; | 978 | bool any_available = false; |
979 | int rc; | 979 | int rc; |
980 | unsigned int refind = 0; | ||
980 | 981 | ||
981 | /* Having a null inode here (because mapping->host was set to zero by | 982 | /* Having a null inode here (because mapping->host was set to zero by |
982 | the VFS or MM) should not happen but we had reports of on oops (due to | 983 | the VFS or MM) should not happen but we had reports of on oops (due to |
@@ -996,40 +997,25 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, | |||
996 | 997 | ||
997 | spin_lock(&cifs_file_list_lock); | 998 | spin_lock(&cifs_file_list_lock); |
998 | refind_writable: | 999 | refind_writable: |
1000 | if (refind > MAX_REOPEN_ATT) { | ||
1001 | spin_unlock(&cifs_file_list_lock); | ||
1002 | return NULL; | ||
1003 | } | ||
999 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | 1004 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { |
1000 | if (!any_available && open_file->pid != current->tgid) | 1005 | if (!any_available && open_file->pid != current->tgid) |
1001 | continue; | 1006 | continue; |
1002 | if (fsuid_only && open_file->uid != current_fsuid()) | 1007 | if (fsuid_only && open_file->uid != current_fsuid()) |
1003 | continue; | 1008 | continue; |
1004 | if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { | 1009 | if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { |
1005 | cifsFileInfo_get(open_file); | ||
1006 | |||
1007 | if (!open_file->invalidHandle) { | 1010 | if (!open_file->invalidHandle) { |
1008 | /* found a good writable file */ | 1011 | /* found a good writable file */ |
1012 | cifsFileInfo_get(open_file); | ||
1009 | spin_unlock(&cifs_file_list_lock); | 1013 | spin_unlock(&cifs_file_list_lock); |
1010 | return open_file; | 1014 | return open_file; |
1015 | } else { | ||
1016 | if (!inv_file) | ||
1017 | inv_file = open_file; | ||
1011 | } | 1018 | } |
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. */ | ||
1033 | } | 1019 | } |
1034 | } | 1020 | } |
1035 | /* couldn't find useable FH with same pid, try any available */ | 1021 | /* couldn't find useable FH with same pid, try any available */ |
@@ -1037,7 +1023,30 @@ refind_writable: | |||
1037 | any_available = true; | 1023 | any_available = true; |
1038 | goto refind_writable; | 1024 | goto refind_writable; |
1039 | } | 1025 | } |
1026 | |||
1027 | if (inv_file) { | ||
1028 | any_available = false; | ||
1029 | cifsFileInfo_get(inv_file); | ||
1030 | } | ||
1031 | |||
1040 | spin_unlock(&cifs_file_list_lock); | 1032 | 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 | |||
1041 | return NULL; | 1050 | return NULL; |
1042 | } | 1051 | } |
1043 | 1052 | ||