diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 57 |
1 files changed, 33 insertions, 24 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index ed9b5a8fb51f..253170dfa716 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -1565,10 +1565,11 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, | |||
1565 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, | 1565 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, |
1566 | bool fsuid_only) | 1566 | bool fsuid_only) |
1567 | { | 1567 | { |
1568 | struct cifsFileInfo *open_file; | 1568 | struct cifsFileInfo *open_file, *inv_file = NULL; |
1569 | struct cifs_sb_info *cifs_sb; | 1569 | struct cifs_sb_info *cifs_sb; |
1570 | bool any_available = false; | 1570 | bool any_available = false; |
1571 | int rc; | 1571 | int rc; |
1572 | unsigned int refind = 0; | ||
1572 | 1573 | ||
1573 | /* Having a null inode here (because mapping->host was set to zero by | 1574 | /* Having a null inode here (because mapping->host was set to zero by |
1574 | the VFS or MM) should not happen but we had reports of on oops (due to | 1575 | the VFS or MM) should not happen but we had reports of on oops (due to |
@@ -1588,40 +1589,25 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, | |||
1588 | 1589 | ||
1589 | spin_lock(&cifs_file_list_lock); | 1590 | spin_lock(&cifs_file_list_lock); |
1590 | refind_writable: | 1591 | refind_writable: |
1592 | if (refind > MAX_REOPEN_ATT) { | ||
1593 | spin_unlock(&cifs_file_list_lock); | ||
1594 | return NULL; | ||
1595 | } | ||
1591 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | 1596 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { |
1592 | if (!any_available && open_file->pid != current->tgid) | 1597 | if (!any_available && open_file->pid != current->tgid) |
1593 | continue; | 1598 | continue; |
1594 | if (fsuid_only && open_file->uid != current_fsuid()) | 1599 | if (fsuid_only && open_file->uid != current_fsuid()) |
1595 | continue; | 1600 | continue; |
1596 | if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { | 1601 | if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { |
1597 | cifsFileInfo_get(open_file); | ||
1598 | |||
1599 | if (!open_file->invalidHandle) { | 1602 | if (!open_file->invalidHandle) { |
1600 | /* found a good writable file */ | 1603 | /* found a good writable file */ |
1604 | cifsFileInfo_get(open_file); | ||
1601 | spin_unlock(&cifs_file_list_lock); | 1605 | spin_unlock(&cifs_file_list_lock); |
1602 | return open_file; | 1606 | return open_file; |
1607 | } else { | ||
1608 | if (!inv_file) | ||
1609 | inv_file = open_file; | ||
1603 | } | 1610 | } |
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. */ | ||
1625 | } | 1611 | } |
1626 | } | 1612 | } |
1627 | /* couldn't find useable FH with same pid, try any available */ | 1613 | /* couldn't find useable FH with same pid, try any available */ |
@@ -1629,7 +1615,30 @@ refind_writable: | |||
1629 | any_available = true; | 1615 | any_available = true; |
1630 | goto refind_writable; | 1616 | goto refind_writable; |
1631 | } | 1617 | } |
1618 | |||
1619 | if (inv_file) { | ||
1620 | any_available = false; | ||
1621 | cifsFileInfo_get(inv_file); | ||
1622 | } | ||
1623 | |||
1632 | spin_unlock(&cifs_file_list_lock); | 1624 | 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 | |||
1633 | return NULL; | 1642 | return NULL; |
1634 | } | 1643 | } |
1635 | 1644 | ||