aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/file.c
diff options
context:
space:
mode:
authorSteve French <smfrench@gmail.com>2016-09-22 19:58:16 -0400
committerSteve French <smfrench@gmail.com>2016-10-12 13:08:32 -0400
commit3afca265b5f53a0b15b79531c13858049505582d (patch)
treeac9c7c97ee38fb4c156731643120833c5e53f63c /fs/cifs/file.c
parentd171356ff11ab1825e456dfb979755e01b3c54a1 (diff)
Clarify locking of cifs file and tcon structures and make more granular
Remove the global file_list_lock to simplify cifs/smb3 locking and have spinlocks that more closely match the information they are protecting. Add new tcon->open_file_lock and file->file_info_lock spinlocks. Locks continue to follow a heirachy, cifs_socket --> cifs_ses --> cifs_tcon --> cifs_file where global tcp_ses_lock still protects socket and cifs_ses, while the the newer locks protect the lower level structure's information (tcon and cifs_file respectively). CC: Stable <stable@vger.kernel.org> Signed-off-by: Steve French <steve.french@primarydata.com> Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com> Reviewed-by: Aurelien Aptel <aaptel@suse.com> Reviewed-by: Germano Percossi <germano.percossi@citrix.com>
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r--fs/cifs/file.c66
1 files changed, 39 insertions, 27 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index a95fe8b1afe9..ee5ceae22411 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -305,6 +305,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
305 cfile->tlink = cifs_get_tlink(tlink); 305 cfile->tlink = cifs_get_tlink(tlink);
306 INIT_WORK(&cfile->oplock_break, cifs_oplock_break); 306 INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
307 mutex_init(&cfile->fh_mutex); 307 mutex_init(&cfile->fh_mutex);
308 spin_lock_init(&cfile->file_info_lock);
308 309
309 cifs_sb_active(inode->i_sb); 310 cifs_sb_active(inode->i_sb);
310 311
@@ -317,7 +318,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
317 oplock = 0; 318 oplock = 0;
318 } 319 }
319 320
320 spin_lock(&cifs_file_list_lock); 321 spin_lock(&tcon->open_file_lock);
321 if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock) 322 if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock)
322 oplock = fid->pending_open->oplock; 323 oplock = fid->pending_open->oplock;
323 list_del(&fid->pending_open->olist); 324 list_del(&fid->pending_open->olist);
@@ -326,12 +327,13 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
326 server->ops->set_fid(cfile, fid, oplock); 327 server->ops->set_fid(cfile, fid, oplock);
327 328
328 list_add(&cfile->tlist, &tcon->openFileList); 329 list_add(&cfile->tlist, &tcon->openFileList);
330
329 /* if readable file instance put first in list*/ 331 /* if readable file instance put first in list*/
330 if (file->f_mode & FMODE_READ) 332 if (file->f_mode & FMODE_READ)
331 list_add(&cfile->flist, &cinode->openFileList); 333 list_add(&cfile->flist, &cinode->openFileList);
332 else 334 else
333 list_add_tail(&cfile->flist, &cinode->openFileList); 335 list_add_tail(&cfile->flist, &cinode->openFileList);
334 spin_unlock(&cifs_file_list_lock); 336 spin_unlock(&tcon->open_file_lock);
335 337
336 if (fid->purge_cache) 338 if (fid->purge_cache)
337 cifs_zap_mapping(inode); 339 cifs_zap_mapping(inode);
@@ -343,16 +345,16 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
343struct cifsFileInfo * 345struct cifsFileInfo *
344cifsFileInfo_get(struct cifsFileInfo *cifs_file) 346cifsFileInfo_get(struct cifsFileInfo *cifs_file)
345{ 347{
346 spin_lock(&cifs_file_list_lock); 348 spin_lock(&cifs_file->file_info_lock);
347 cifsFileInfo_get_locked(cifs_file); 349 cifsFileInfo_get_locked(cifs_file);
348 spin_unlock(&cifs_file_list_lock); 350 spin_unlock(&cifs_file->file_info_lock);
349 return cifs_file; 351 return cifs_file;
350} 352}
351 353
352/* 354/*
353 * Release a reference on the file private data. This may involve closing 355 * Release a reference on the file private data. This may involve closing
354 * the filehandle out on the server. Must be called without holding 356 * the filehandle out on the server. Must be called without holding
355 * cifs_file_list_lock. 357 * tcon->open_file_lock and cifs_file->file_info_lock.
356 */ 358 */
357void cifsFileInfo_put(struct cifsFileInfo *cifs_file) 359void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
358{ 360{
@@ -367,11 +369,15 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
367 struct cifs_pending_open open; 369 struct cifs_pending_open open;
368 bool oplock_break_cancelled; 370 bool oplock_break_cancelled;
369 371
370 spin_lock(&cifs_file_list_lock); 372 spin_lock(&tcon->open_file_lock);
373
374 spin_lock(&cifs_file->file_info_lock);
371 if (--cifs_file->count > 0) { 375 if (--cifs_file->count > 0) {
372 spin_unlock(&cifs_file_list_lock); 376 spin_unlock(&cifs_file->file_info_lock);
377 spin_unlock(&tcon->open_file_lock);
373 return; 378 return;
374 } 379 }
380 spin_unlock(&cifs_file->file_info_lock);
375 381
376 if (server->ops->get_lease_key) 382 if (server->ops->get_lease_key)
377 server->ops->get_lease_key(inode, &fid); 383 server->ops->get_lease_key(inode, &fid);
@@ -395,7 +401,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
395 set_bit(CIFS_INO_INVALID_MAPPING, &cifsi->flags); 401 set_bit(CIFS_INO_INVALID_MAPPING, &cifsi->flags);
396 cifs_set_oplock_level(cifsi, 0); 402 cifs_set_oplock_level(cifsi, 0);
397 } 403 }
398 spin_unlock(&cifs_file_list_lock); 404
405 spin_unlock(&tcon->open_file_lock);
399 406
400 oplock_break_cancelled = cancel_work_sync(&cifs_file->oplock_break); 407 oplock_break_cancelled = cancel_work_sync(&cifs_file->oplock_break);
401 408
@@ -772,10 +779,10 @@ int cifs_closedir(struct inode *inode, struct file *file)
772 server = tcon->ses->server; 779 server = tcon->ses->server;
773 780
774 cifs_dbg(FYI, "Freeing private data in close dir\n"); 781 cifs_dbg(FYI, "Freeing private data in close dir\n");
775 spin_lock(&cifs_file_list_lock); 782 spin_lock(&cfile->file_info_lock);
776 if (server->ops->dir_needs_close(cfile)) { 783 if (server->ops->dir_needs_close(cfile)) {
777 cfile->invalidHandle = true; 784 cfile->invalidHandle = true;
778 spin_unlock(&cifs_file_list_lock); 785 spin_unlock(&cfile->file_info_lock);
779 if (server->ops->close_dir) 786 if (server->ops->close_dir)
780 rc = server->ops->close_dir(xid, tcon, &cfile->fid); 787 rc = server->ops->close_dir(xid, tcon, &cfile->fid);
781 else 788 else
@@ -784,7 +791,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
784 /* not much we can do if it fails anyway, ignore rc */ 791 /* not much we can do if it fails anyway, ignore rc */
785 rc = 0; 792 rc = 0;
786 } else 793 } else
787 spin_unlock(&cifs_file_list_lock); 794 spin_unlock(&cfile->file_info_lock);
788 795
789 buf = cfile->srch_inf.ntwrk_buf_start; 796 buf = cfile->srch_inf.ntwrk_buf_start;
790 if (buf) { 797 if (buf) {
@@ -1728,12 +1735,13 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
1728{ 1735{
1729 struct cifsFileInfo *open_file = NULL; 1736 struct cifsFileInfo *open_file = NULL;
1730 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); 1737 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1738 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
1731 1739
1732 /* only filter by fsuid on multiuser mounts */ 1740 /* only filter by fsuid on multiuser mounts */
1733 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) 1741 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1734 fsuid_only = false; 1742 fsuid_only = false;
1735 1743
1736 spin_lock(&cifs_file_list_lock); 1744 spin_lock(&tcon->open_file_lock);
1737 /* we could simply get the first_list_entry since write-only entries 1745 /* we could simply get the first_list_entry since write-only entries
1738 are always at the end of the list but since the first entry might 1746 are always at the end of the list but since the first entry might
1739 have a close pending, we go through the whole list */ 1747 have a close pending, we go through the whole list */
@@ -1744,8 +1752,8 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
1744 if (!open_file->invalidHandle) { 1752 if (!open_file->invalidHandle) {
1745 /* found a good file */ 1753 /* found a good file */
1746 /* lock it so it will not be closed on us */ 1754 /* lock it so it will not be closed on us */
1747 cifsFileInfo_get_locked(open_file); 1755 cifsFileInfo_get(open_file);
1748 spin_unlock(&cifs_file_list_lock); 1756 spin_unlock(&tcon->open_file_lock);
1749 return open_file; 1757 return open_file;
1750 } /* else might as well continue, and look for 1758 } /* else might as well continue, and look for
1751 another, or simply have the caller reopen it 1759 another, or simply have the caller reopen it
@@ -1753,7 +1761,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
1753 } else /* write only file */ 1761 } else /* write only file */
1754 break; /* write only files are last so must be done */ 1762 break; /* write only files are last so must be done */
1755 } 1763 }
1756 spin_unlock(&cifs_file_list_lock); 1764 spin_unlock(&tcon->open_file_lock);
1757 return NULL; 1765 return NULL;
1758} 1766}
1759 1767
@@ -1762,6 +1770,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
1762{ 1770{
1763 struct cifsFileInfo *open_file, *inv_file = NULL; 1771 struct cifsFileInfo *open_file, *inv_file = NULL;
1764 struct cifs_sb_info *cifs_sb; 1772 struct cifs_sb_info *cifs_sb;
1773 struct cifs_tcon *tcon;
1765 bool any_available = false; 1774 bool any_available = false;
1766 int rc; 1775 int rc;
1767 unsigned int refind = 0; 1776 unsigned int refind = 0;
@@ -1777,15 +1786,16 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
1777 } 1786 }
1778 1787
1779 cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); 1788 cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1789 tcon = cifs_sb_master_tcon(cifs_sb);
1780 1790
1781 /* only filter by fsuid on multiuser mounts */ 1791 /* only filter by fsuid on multiuser mounts */
1782 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) 1792 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1783 fsuid_only = false; 1793 fsuid_only = false;
1784 1794
1785 spin_lock(&cifs_file_list_lock); 1795 spin_lock(&tcon->open_file_lock);
1786refind_writable: 1796refind_writable:
1787 if (refind > MAX_REOPEN_ATT) { 1797 if (refind > MAX_REOPEN_ATT) {
1788 spin_unlock(&cifs_file_list_lock); 1798 spin_unlock(&tcon->open_file_lock);
1789 return NULL; 1799 return NULL;
1790 } 1800 }
1791 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { 1801 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
@@ -1796,8 +1806,8 @@ refind_writable:
1796 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { 1806 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
1797 if (!open_file->invalidHandle) { 1807 if (!open_file->invalidHandle) {
1798 /* found a good writable file */ 1808 /* found a good writable file */
1799 cifsFileInfo_get_locked(open_file); 1809 cifsFileInfo_get(open_file);
1800 spin_unlock(&cifs_file_list_lock); 1810 spin_unlock(&tcon->open_file_lock);
1801 return open_file; 1811 return open_file;
1802 } else { 1812 } else {
1803 if (!inv_file) 1813 if (!inv_file)
@@ -1813,24 +1823,24 @@ refind_writable:
1813 1823
1814 if (inv_file) { 1824 if (inv_file) {
1815 any_available = false; 1825 any_available = false;
1816 cifsFileInfo_get_locked(inv_file); 1826 cifsFileInfo_get(inv_file);
1817 } 1827 }
1818 1828
1819 spin_unlock(&cifs_file_list_lock); 1829 spin_unlock(&tcon->open_file_lock);
1820 1830
1821 if (inv_file) { 1831 if (inv_file) {
1822 rc = cifs_reopen_file(inv_file, false); 1832 rc = cifs_reopen_file(inv_file, false);
1823 if (!rc) 1833 if (!rc)
1824 return inv_file; 1834 return inv_file;
1825 else { 1835 else {
1826 spin_lock(&cifs_file_list_lock); 1836 spin_lock(&tcon->open_file_lock);
1827 list_move_tail(&inv_file->flist, 1837 list_move_tail(&inv_file->flist,
1828 &cifs_inode->openFileList); 1838 &cifs_inode->openFileList);
1829 spin_unlock(&cifs_file_list_lock); 1839 spin_unlock(&tcon->open_file_lock);
1830 cifsFileInfo_put(inv_file); 1840 cifsFileInfo_put(inv_file);
1831 spin_lock(&cifs_file_list_lock);
1832 ++refind; 1841 ++refind;
1833 inv_file = NULL; 1842 inv_file = NULL;
1843 spin_lock(&tcon->open_file_lock);
1834 goto refind_writable; 1844 goto refind_writable;
1835 } 1845 }
1836 } 1846 }
@@ -3612,15 +3622,17 @@ static int cifs_readpage(struct file *file, struct page *page)
3612static int is_inode_writable(struct cifsInodeInfo *cifs_inode) 3622static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
3613{ 3623{
3614 struct cifsFileInfo *open_file; 3624 struct cifsFileInfo *open_file;
3625 struct cifs_tcon *tcon =
3626 cifs_sb_master_tcon(CIFS_SB(cifs_inode->vfs_inode.i_sb));
3615 3627
3616 spin_lock(&cifs_file_list_lock); 3628 spin_lock(&tcon->open_file_lock);
3617 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { 3629 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
3618 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { 3630 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
3619 spin_unlock(&cifs_file_list_lock); 3631 spin_unlock(&tcon->open_file_lock);
3620 return 1; 3632 return 1;
3621 } 3633 }
3622 } 3634 }
3623 spin_unlock(&cifs_file_list_lock); 3635 spin_unlock(&tcon->open_file_lock);
3624 return 0; 3636 return 0;
3625} 3637}
3626 3638