diff options
-rw-r--r-- | fs/ceph/file.c | 2 | ||||
-rw-r--r-- | fs/ceph/inode.c | 124 | ||||
-rw-r--r-- | fs/ceph/super.c | 28 | ||||
-rw-r--r-- | fs/ceph/super.h | 17 |
4 files changed, 74 insertions, 97 deletions
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 305daf043eb0..183c37c0a8fc 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c | |||
@@ -791,7 +791,7 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req) | |||
791 | if (aio_work) { | 791 | if (aio_work) { |
792 | INIT_WORK(&aio_work->work, ceph_aio_retry_work); | 792 | INIT_WORK(&aio_work->work, ceph_aio_retry_work); |
793 | aio_work->req = req; | 793 | aio_work->req = req; |
794 | queue_work(ceph_inode_to_client(inode)->wb_wq, | 794 | queue_work(ceph_inode_to_client(inode)->inode_wq, |
795 | &aio_work->work); | 795 | &aio_work->work); |
796 | return; | 796 | return; |
797 | } | 797 | } |
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index f85355bf49c4..3acdd3cc6039 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
@@ -33,9 +33,7 @@ | |||
33 | 33 | ||
34 | static const struct inode_operations ceph_symlink_iops; | 34 | static const struct inode_operations ceph_symlink_iops; |
35 | 35 | ||
36 | static void ceph_invalidate_work(struct work_struct *work); | 36 | static void ceph_inode_work(struct work_struct *work); |
37 | static void ceph_writeback_work(struct work_struct *work); | ||
38 | static void ceph_vmtruncate_work(struct work_struct *work); | ||
39 | 37 | ||
40 | /* | 38 | /* |
41 | * find or create an inode, given the ceph ino number | 39 | * find or create an inode, given the ceph ino number |
@@ -509,10 +507,8 @@ struct inode *ceph_alloc_inode(struct super_block *sb) | |||
509 | INIT_LIST_HEAD(&ci->i_snap_realm_item); | 507 | INIT_LIST_HEAD(&ci->i_snap_realm_item); |
510 | INIT_LIST_HEAD(&ci->i_snap_flush_item); | 508 | INIT_LIST_HEAD(&ci->i_snap_flush_item); |
511 | 509 | ||
512 | INIT_WORK(&ci->i_wb_work, ceph_writeback_work); | 510 | INIT_WORK(&ci->i_work, ceph_inode_work); |
513 | INIT_WORK(&ci->i_pg_inv_work, ceph_invalidate_work); | 511 | ci->i_work_mask = 0; |
514 | |||
515 | INIT_WORK(&ci->i_vmtruncate_work, ceph_vmtruncate_work); | ||
516 | 512 | ||
517 | ceph_fscache_inode_init(ci); | 513 | ceph_fscache_inode_init(ci); |
518 | 514 | ||
@@ -1746,51 +1742,62 @@ bool ceph_inode_set_size(struct inode *inode, loff_t size) | |||
1746 | */ | 1742 | */ |
1747 | void ceph_queue_writeback(struct inode *inode) | 1743 | void ceph_queue_writeback(struct inode *inode) |
1748 | { | 1744 | { |
1745 | struct ceph_inode_info *ci = ceph_inode(inode); | ||
1746 | set_bit(CEPH_I_WORK_WRITEBACK, &ci->i_work_mask); | ||
1747 | |||
1749 | ihold(inode); | 1748 | ihold(inode); |
1750 | if (queue_work(ceph_inode_to_client(inode)->wb_wq, | 1749 | if (queue_work(ceph_inode_to_client(inode)->inode_wq, |
1751 | &ceph_inode(inode)->i_wb_work)) { | 1750 | &ci->i_work)) { |
1752 | dout("ceph_queue_writeback %p\n", inode); | 1751 | dout("ceph_queue_writeback %p\n", inode); |
1753 | } else { | 1752 | } else { |
1754 | dout("ceph_queue_writeback %p failed\n", inode); | 1753 | dout("ceph_queue_writeback %p already queued, mask=%lx\n", |
1754 | inode, ci->i_work_mask); | ||
1755 | iput(inode); | 1755 | iput(inode); |
1756 | } | 1756 | } |
1757 | } | 1757 | } |
1758 | 1758 | ||
1759 | static void ceph_writeback_work(struct work_struct *work) | ||
1760 | { | ||
1761 | struct ceph_inode_info *ci = container_of(work, struct ceph_inode_info, | ||
1762 | i_wb_work); | ||
1763 | struct inode *inode = &ci->vfs_inode; | ||
1764 | |||
1765 | dout("writeback %p\n", inode); | ||
1766 | filemap_fdatawrite(&inode->i_data); | ||
1767 | iput(inode); | ||
1768 | } | ||
1769 | |||
1770 | /* | 1759 | /* |
1771 | * queue an async invalidation | 1760 | * queue an async invalidation |
1772 | */ | 1761 | */ |
1773 | void ceph_queue_invalidate(struct inode *inode) | 1762 | void ceph_queue_invalidate(struct inode *inode) |
1774 | { | 1763 | { |
1764 | struct ceph_inode_info *ci = ceph_inode(inode); | ||
1765 | set_bit(CEPH_I_WORK_INVALIDATE_PAGES, &ci->i_work_mask); | ||
1766 | |||
1775 | ihold(inode); | 1767 | ihold(inode); |
1776 | if (queue_work(ceph_inode_to_client(inode)->pg_inv_wq, | 1768 | if (queue_work(ceph_inode_to_client(inode)->inode_wq, |
1777 | &ceph_inode(inode)->i_pg_inv_work)) { | 1769 | &ceph_inode(inode)->i_work)) { |
1778 | dout("ceph_queue_invalidate %p\n", inode); | 1770 | dout("ceph_queue_invalidate %p\n", inode); |
1779 | } else { | 1771 | } else { |
1780 | dout("ceph_queue_invalidate %p failed\n", inode); | 1772 | dout("ceph_queue_invalidate %p already queued, mask=%lx\n", |
1773 | inode, ci->i_work_mask); | ||
1781 | iput(inode); | 1774 | iput(inode); |
1782 | } | 1775 | } |
1783 | } | 1776 | } |
1784 | 1777 | ||
1785 | /* | 1778 | /* |
1786 | * Invalidate inode pages in a worker thread. (This can't be done | 1779 | * Queue an async vmtruncate. If we fail to queue work, we will handle |
1787 | * in the message handler context.) | 1780 | * the truncation the next time we call __ceph_do_pending_vmtruncate. |
1788 | */ | 1781 | */ |
1789 | static void ceph_invalidate_work(struct work_struct *work) | 1782 | void ceph_queue_vmtruncate(struct inode *inode) |
1790 | { | 1783 | { |
1791 | struct ceph_inode_info *ci = container_of(work, struct ceph_inode_info, | 1784 | struct ceph_inode_info *ci = ceph_inode(inode); |
1792 | i_pg_inv_work); | 1785 | set_bit(CEPH_I_WORK_VMTRUNCATE, &ci->i_work_mask); |
1793 | struct inode *inode = &ci->vfs_inode; | 1786 | |
1787 | ihold(inode); | ||
1788 | if (queue_work(ceph_inode_to_client(inode)->inode_wq, | ||
1789 | &ci->i_work)) { | ||
1790 | dout("ceph_queue_vmtruncate %p\n", inode); | ||
1791 | } else { | ||
1792 | dout("ceph_queue_vmtruncate %p already queued, mask=%lx\n", | ||
1793 | inode, ci->i_work_mask); | ||
1794 | iput(inode); | ||
1795 | } | ||
1796 | } | ||
1797 | |||
1798 | static void ceph_do_invalidate_pages(struct inode *inode) | ||
1799 | { | ||
1800 | struct ceph_inode_info *ci = ceph_inode(inode); | ||
1794 | struct ceph_fs_client *fsc = ceph_inode_to_client(inode); | 1801 | struct ceph_fs_client *fsc = ceph_inode_to_client(inode); |
1795 | u32 orig_gen; | 1802 | u32 orig_gen; |
1796 | int check = 0; | 1803 | int check = 0; |
@@ -1842,44 +1849,6 @@ static void ceph_invalidate_work(struct work_struct *work) | |||
1842 | out: | 1849 | out: |
1843 | if (check) | 1850 | if (check) |
1844 | ceph_check_caps(ci, 0, NULL); | 1851 | ceph_check_caps(ci, 0, NULL); |
1845 | iput(inode); | ||
1846 | } | ||
1847 | |||
1848 | |||
1849 | /* | ||
1850 | * called by trunc_wq; | ||
1851 | * | ||
1852 | * We also truncate in a separate thread as well. | ||
1853 | */ | ||
1854 | static void ceph_vmtruncate_work(struct work_struct *work) | ||
1855 | { | ||
1856 | struct ceph_inode_info *ci = container_of(work, struct ceph_inode_info, | ||
1857 | i_vmtruncate_work); | ||
1858 | struct inode *inode = &ci->vfs_inode; | ||
1859 | |||
1860 | dout("vmtruncate_work %p\n", inode); | ||
1861 | __ceph_do_pending_vmtruncate(inode); | ||
1862 | iput(inode); | ||
1863 | } | ||
1864 | |||
1865 | /* | ||
1866 | * Queue an async vmtruncate. If we fail to queue work, we will handle | ||
1867 | * the truncation the next time we call __ceph_do_pending_vmtruncate. | ||
1868 | */ | ||
1869 | void ceph_queue_vmtruncate(struct inode *inode) | ||
1870 | { | ||
1871 | struct ceph_inode_info *ci = ceph_inode(inode); | ||
1872 | |||
1873 | ihold(inode); | ||
1874 | |||
1875 | if (queue_work(ceph_sb_to_client(inode->i_sb)->trunc_wq, | ||
1876 | &ci->i_vmtruncate_work)) { | ||
1877 | dout("ceph_queue_vmtruncate %p\n", inode); | ||
1878 | } else { | ||
1879 | dout("ceph_queue_vmtruncate %p failed, pending=%d\n", | ||
1880 | inode, ci->i_truncate_pending); | ||
1881 | iput(inode); | ||
1882 | } | ||
1883 | } | 1852 | } |
1884 | 1853 | ||
1885 | /* | 1854 | /* |
@@ -1943,6 +1912,25 @@ retry: | |||
1943 | wake_up_all(&ci->i_cap_wq); | 1912 | wake_up_all(&ci->i_cap_wq); |
1944 | } | 1913 | } |
1945 | 1914 | ||
1915 | static void ceph_inode_work(struct work_struct *work) | ||
1916 | { | ||
1917 | struct ceph_inode_info *ci = container_of(work, struct ceph_inode_info, | ||
1918 | i_work); | ||
1919 | struct inode *inode = &ci->vfs_inode; | ||
1920 | |||
1921 | if (test_and_clear_bit(CEPH_I_WORK_WRITEBACK, &ci->i_work_mask)) { | ||
1922 | dout("writeback %p\n", inode); | ||
1923 | filemap_fdatawrite(&inode->i_data); | ||
1924 | } | ||
1925 | if (test_and_clear_bit(CEPH_I_WORK_INVALIDATE_PAGES, &ci->i_work_mask)) | ||
1926 | ceph_do_invalidate_pages(inode); | ||
1927 | |||
1928 | if (test_and_clear_bit(CEPH_I_WORK_VMTRUNCATE, &ci->i_work_mask)) | ||
1929 | __ceph_do_pending_vmtruncate(inode); | ||
1930 | |||
1931 | iput(inode); | ||
1932 | } | ||
1933 | |||
1946 | /* | 1934 | /* |
1947 | * symlinks | 1935 | * symlinks |
1948 | */ | 1936 | */ |
diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 01be7c1bc4c6..d57fa60dcd43 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c | |||
@@ -672,18 +672,12 @@ static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt, | |||
672 | * The number of concurrent works can be high but they don't need | 672 | * The number of concurrent works can be high but they don't need |
673 | * to be processed in parallel, limit concurrency. | 673 | * to be processed in parallel, limit concurrency. |
674 | */ | 674 | */ |
675 | fsc->wb_wq = alloc_workqueue("ceph-writeback", 0, 1); | 675 | fsc->inode_wq = alloc_workqueue("ceph-inode", WQ_UNBOUND, 0); |
676 | if (!fsc->wb_wq) | 676 | if (!fsc->inode_wq) |
677 | goto fail_client; | 677 | goto fail_client; |
678 | fsc->pg_inv_wq = alloc_workqueue("ceph-pg-invalid", 0, 1); | ||
679 | if (!fsc->pg_inv_wq) | ||
680 | goto fail_wb_wq; | ||
681 | fsc->trunc_wq = alloc_workqueue("ceph-trunc", 0, 1); | ||
682 | if (!fsc->trunc_wq) | ||
683 | goto fail_pg_inv_wq; | ||
684 | fsc->cap_wq = alloc_workqueue("ceph-cap", 0, 1); | 678 | fsc->cap_wq = alloc_workqueue("ceph-cap", 0, 1); |
685 | if (!fsc->cap_wq) | 679 | if (!fsc->cap_wq) |
686 | goto fail_trunc_wq; | 680 | goto fail_inode_wq; |
687 | 681 | ||
688 | /* set up mempools */ | 682 | /* set up mempools */ |
689 | err = -ENOMEM; | 683 | err = -ENOMEM; |
@@ -697,12 +691,8 @@ static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt, | |||
697 | 691 | ||
698 | fail_cap_wq: | 692 | fail_cap_wq: |
699 | destroy_workqueue(fsc->cap_wq); | 693 | destroy_workqueue(fsc->cap_wq); |
700 | fail_trunc_wq: | 694 | fail_inode_wq: |
701 | destroy_workqueue(fsc->trunc_wq); | 695 | destroy_workqueue(fsc->inode_wq); |
702 | fail_pg_inv_wq: | ||
703 | destroy_workqueue(fsc->pg_inv_wq); | ||
704 | fail_wb_wq: | ||
705 | destroy_workqueue(fsc->wb_wq); | ||
706 | fail_client: | 696 | fail_client: |
707 | ceph_destroy_client(fsc->client); | 697 | ceph_destroy_client(fsc->client); |
708 | fail: | 698 | fail: |
@@ -715,9 +705,7 @@ fail: | |||
715 | 705 | ||
716 | static void flush_fs_workqueues(struct ceph_fs_client *fsc) | 706 | static void flush_fs_workqueues(struct ceph_fs_client *fsc) |
717 | { | 707 | { |
718 | flush_workqueue(fsc->wb_wq); | 708 | flush_workqueue(fsc->inode_wq); |
719 | flush_workqueue(fsc->pg_inv_wq); | ||
720 | flush_workqueue(fsc->trunc_wq); | ||
721 | flush_workqueue(fsc->cap_wq); | 709 | flush_workqueue(fsc->cap_wq); |
722 | } | 710 | } |
723 | 711 | ||
@@ -725,9 +713,7 @@ static void destroy_fs_client(struct ceph_fs_client *fsc) | |||
725 | { | 713 | { |
726 | dout("destroy_fs_client %p\n", fsc); | 714 | dout("destroy_fs_client %p\n", fsc); |
727 | 715 | ||
728 | destroy_workqueue(fsc->wb_wq); | 716 | destroy_workqueue(fsc->inode_wq); |
729 | destroy_workqueue(fsc->pg_inv_wq); | ||
730 | destroy_workqueue(fsc->trunc_wq); | ||
731 | destroy_workqueue(fsc->cap_wq); | 717 | destroy_workqueue(fsc->cap_wq); |
732 | 718 | ||
733 | mempool_destroy(fsc->wb_pagevec_pool); | 719 | mempool_destroy(fsc->wb_pagevec_pool); |
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 6edab9a750f8..3fb866a979ce 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h | |||
@@ -109,9 +109,7 @@ struct ceph_fs_client { | |||
109 | mempool_t *wb_pagevec_pool; | 109 | mempool_t *wb_pagevec_pool; |
110 | atomic_long_t writeback_count; | 110 | atomic_long_t writeback_count; |
111 | 111 | ||
112 | struct workqueue_struct *wb_wq; | 112 | struct workqueue_struct *inode_wq; |
113 | struct workqueue_struct *pg_inv_wq; | ||
114 | struct workqueue_struct *trunc_wq; | ||
115 | struct workqueue_struct *cap_wq; | 113 | struct workqueue_struct *cap_wq; |
116 | 114 | ||
117 | #ifdef CONFIG_DEBUG_FS | 115 | #ifdef CONFIG_DEBUG_FS |
@@ -387,10 +385,8 @@ struct ceph_inode_info { | |||
387 | struct list_head i_snap_realm_item; | 385 | struct list_head i_snap_realm_item; |
388 | struct list_head i_snap_flush_item; | 386 | struct list_head i_snap_flush_item; |
389 | 387 | ||
390 | struct work_struct i_wb_work; /* writeback work */ | 388 | struct work_struct i_work; |
391 | struct work_struct i_pg_inv_work; /* page invalidation work */ | 389 | unsigned long i_work_mask; |
392 | |||
393 | struct work_struct i_vmtruncate_work; | ||
394 | 390 | ||
395 | #ifdef CONFIG_CEPH_FSCACHE | 391 | #ifdef CONFIG_CEPH_FSCACHE |
396 | struct fscache_cookie *fscache; | 392 | struct fscache_cookie *fscache; |
@@ -513,6 +509,13 @@ static inline struct inode *ceph_find_inode(struct super_block *sb, | |||
513 | 509 | ||
514 | 510 | ||
515 | /* | 511 | /* |
512 | * Masks of ceph inode work. | ||
513 | */ | ||
514 | #define CEPH_I_WORK_WRITEBACK 0 /* writeback */ | ||
515 | #define CEPH_I_WORK_INVALIDATE_PAGES 1 /* invalidate pages */ | ||
516 | #define CEPH_I_WORK_VMTRUNCATE 2 /* vmtruncate */ | ||
517 | |||
518 | /* | ||
516 | * We set the ERROR_WRITE bit when we start seeing write errors on an inode | 519 | * We set the ERROR_WRITE bit when we start seeing write errors on an inode |
517 | * and then clear it when they start succeeding. Note that we do a lockless | 520 | * and then clear it when they start succeeding. Note that we do a lockless |
518 | * check first, and only take the lock if it looks like it needs to be changed. | 521 | * check first, and only take the lock if it looks like it needs to be changed. |