diff options
Diffstat (limited to 'fs/ceph')
-rw-r--r-- | fs/ceph/addr.c | 12 | ||||
-rw-r--r-- | fs/ceph/caps.c | 91 | ||||
-rw-r--r-- | fs/ceph/dir.c | 7 | ||||
-rw-r--r-- | fs/ceph/export.c | 25 | ||||
-rw-r--r-- | fs/ceph/file.c | 5 | ||||
-rw-r--r-- | fs/ceph/inode.c | 7 | ||||
-rw-r--r-- | fs/ceph/mds_client.c | 9 | ||||
-rw-r--r-- | fs/ceph/mds_client.h | 1 | ||||
-rw-r--r-- | fs/ceph/snap.c | 2 | ||||
-rw-r--r-- | fs/ceph/super.h | 4 | ||||
-rw-r--r-- | fs/ceph/xattr.c | 12 |
11 files changed, 109 insertions, 66 deletions
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index e159c529fd2b..33da49dc3cc6 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c | |||
@@ -775,6 +775,13 @@ get_more_pages: | |||
775 | ci->i_truncate_seq, | 775 | ci->i_truncate_seq, |
776 | ci->i_truncate_size, | 776 | ci->i_truncate_size, |
777 | &inode->i_mtime, true, 1, 0); | 777 | &inode->i_mtime, true, 1, 0); |
778 | |||
779 | if (!req) { | ||
780 | rc = -ENOMEM; | ||
781 | unlock_page(page); | ||
782 | break; | ||
783 | } | ||
784 | |||
778 | max_pages = req->r_num_pages; | 785 | max_pages = req->r_num_pages; |
779 | 786 | ||
780 | alloc_page_vec(fsc, req); | 787 | alloc_page_vec(fsc, req); |
@@ -841,7 +848,8 @@ get_more_pages: | |||
841 | op->payload_len = cpu_to_le32(len); | 848 | op->payload_len = cpu_to_le32(len); |
842 | req->r_request->hdr.data_len = cpu_to_le32(len); | 849 | req->r_request->hdr.data_len = cpu_to_le32(len); |
843 | 850 | ||
844 | ceph_osdc_start_request(&fsc->client->osdc, req, true); | 851 | rc = ceph_osdc_start_request(&fsc->client->osdc, req, true); |
852 | BUG_ON(rc); | ||
845 | req = NULL; | 853 | req = NULL; |
846 | 854 | ||
847 | /* continue? */ | 855 | /* continue? */ |
@@ -873,8 +881,6 @@ release_pvec_pages: | |||
873 | out: | 881 | out: |
874 | if (req) | 882 | if (req) |
875 | ceph_osdc_put_request(req); | 883 | ceph_osdc_put_request(req); |
876 | if (rc > 0) | ||
877 | rc = 0; /* vfs expects us to return 0 */ | ||
878 | ceph_put_snap_context(snapc); | 884 | ceph_put_snap_context(snapc); |
879 | dout("writepages done, rc = %d\n", rc); | 885 | dout("writepages done, rc = %d\n", rc); |
880 | return rc; | 886 | return rc; |
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 5323c330bbf3..1f72b00447c4 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
@@ -569,7 +569,8 @@ retry: | |||
569 | list_add_tail(&cap->session_caps, &session->s_caps); | 569 | list_add_tail(&cap->session_caps, &session->s_caps); |
570 | session->s_nr_caps++; | 570 | session->s_nr_caps++; |
571 | spin_unlock(&session->s_cap_lock); | 571 | spin_unlock(&session->s_cap_lock); |
572 | } | 572 | } else if (new_cap) |
573 | ceph_put_cap(mdsc, new_cap); | ||
573 | 574 | ||
574 | if (!ci->i_snap_realm) { | 575 | if (!ci->i_snap_realm) { |
575 | /* | 576 | /* |
@@ -819,7 +820,7 @@ int __ceph_caps_used(struct ceph_inode_info *ci) | |||
819 | used |= CEPH_CAP_FILE_CACHE; | 820 | used |= CEPH_CAP_FILE_CACHE; |
820 | if (ci->i_wr_ref) | 821 | if (ci->i_wr_ref) |
821 | used |= CEPH_CAP_FILE_WR; | 822 | used |= CEPH_CAP_FILE_WR; |
822 | if (ci->i_wrbuffer_ref) | 823 | if (ci->i_wb_ref || ci->i_wrbuffer_ref) |
823 | used |= CEPH_CAP_FILE_BUFFER; | 824 | used |= CEPH_CAP_FILE_BUFFER; |
824 | return used; | 825 | return used; |
825 | } | 826 | } |
@@ -1331,10 +1332,11 @@ static void ceph_flush_snaps(struct ceph_inode_info *ci) | |||
1331 | } | 1332 | } |
1332 | 1333 | ||
1333 | /* | 1334 | /* |
1334 | * Mark caps dirty. If inode is newly dirty, add to the global dirty | 1335 | * Mark caps dirty. If inode is newly dirty, return the dirty flags. |
1335 | * list. | 1336 | * Caller is then responsible for calling __mark_inode_dirty with the |
1337 | * returned flags value. | ||
1336 | */ | 1338 | */ |
1337 | void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) | 1339 | int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) |
1338 | { | 1340 | { |
1339 | struct ceph_mds_client *mdsc = | 1341 | struct ceph_mds_client *mdsc = |
1340 | ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc; | 1342 | ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc; |
@@ -1357,7 +1359,7 @@ void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) | |||
1357 | list_add(&ci->i_dirty_item, &mdsc->cap_dirty); | 1359 | list_add(&ci->i_dirty_item, &mdsc->cap_dirty); |
1358 | spin_unlock(&mdsc->cap_dirty_lock); | 1360 | spin_unlock(&mdsc->cap_dirty_lock); |
1359 | if (ci->i_flushing_caps == 0) { | 1361 | if (ci->i_flushing_caps == 0) { |
1360 | igrab(inode); | 1362 | ihold(inode); |
1361 | dirty |= I_DIRTY_SYNC; | 1363 | dirty |= I_DIRTY_SYNC; |
1362 | } | 1364 | } |
1363 | } | 1365 | } |
@@ -1365,9 +1367,8 @@ void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) | |||
1365 | if (((was | ci->i_flushing_caps) & CEPH_CAP_FILE_BUFFER) && | 1367 | if (((was | ci->i_flushing_caps) & CEPH_CAP_FILE_BUFFER) && |
1366 | (mask & CEPH_CAP_FILE_BUFFER)) | 1368 | (mask & CEPH_CAP_FILE_BUFFER)) |
1367 | dirty |= I_DIRTY_DATASYNC; | 1369 | dirty |= I_DIRTY_DATASYNC; |
1368 | if (dirty) | ||
1369 | __mark_inode_dirty(inode, dirty); | ||
1370 | __cap_delay_requeue(mdsc, ci); | 1370 | __cap_delay_requeue(mdsc, ci); |
1371 | return dirty; | ||
1371 | } | 1372 | } |
1372 | 1373 | ||
1373 | /* | 1374 | /* |
@@ -1990,11 +1991,11 @@ static void __take_cap_refs(struct ceph_inode_info *ci, int got) | |||
1990 | if (got & CEPH_CAP_FILE_WR) | 1991 | if (got & CEPH_CAP_FILE_WR) |
1991 | ci->i_wr_ref++; | 1992 | ci->i_wr_ref++; |
1992 | if (got & CEPH_CAP_FILE_BUFFER) { | 1993 | if (got & CEPH_CAP_FILE_BUFFER) { |
1993 | if (ci->i_wrbuffer_ref == 0) | 1994 | if (ci->i_wb_ref == 0) |
1994 | igrab(&ci->vfs_inode); | 1995 | ihold(&ci->vfs_inode); |
1995 | ci->i_wrbuffer_ref++; | 1996 | ci->i_wb_ref++; |
1996 | dout("__take_cap_refs %p wrbuffer %d -> %d (?)\n", | 1997 | dout("__take_cap_refs %p wb %d -> %d (?)\n", |
1997 | &ci->vfs_inode, ci->i_wrbuffer_ref-1, ci->i_wrbuffer_ref); | 1998 | &ci->vfs_inode, ci->i_wb_ref-1, ci->i_wb_ref); |
1998 | } | 1999 | } |
1999 | } | 2000 | } |
2000 | 2001 | ||
@@ -2169,12 +2170,12 @@ void ceph_put_cap_refs(struct ceph_inode_info *ci, int had) | |||
2169 | if (--ci->i_rdcache_ref == 0) | 2170 | if (--ci->i_rdcache_ref == 0) |
2170 | last++; | 2171 | last++; |
2171 | if (had & CEPH_CAP_FILE_BUFFER) { | 2172 | if (had & CEPH_CAP_FILE_BUFFER) { |
2172 | if (--ci->i_wrbuffer_ref == 0) { | 2173 | if (--ci->i_wb_ref == 0) { |
2173 | last++; | 2174 | last++; |
2174 | put++; | 2175 | put++; |
2175 | } | 2176 | } |
2176 | dout("put_cap_refs %p wrbuffer %d -> %d (?)\n", | 2177 | dout("put_cap_refs %p wb %d -> %d (?)\n", |
2177 | inode, ci->i_wrbuffer_ref+1, ci->i_wrbuffer_ref); | 2178 | inode, ci->i_wb_ref+1, ci->i_wb_ref); |
2178 | } | 2179 | } |
2179 | if (had & CEPH_CAP_FILE_WR) | 2180 | if (had & CEPH_CAP_FILE_WR) |
2180 | if (--ci->i_wr_ref == 0) { | 2181 | if (--ci->i_wr_ref == 0) { |
@@ -2634,6 +2635,7 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex, | |||
2634 | struct ceph_mds_session *session, | 2635 | struct ceph_mds_session *session, |
2635 | int *open_target_sessions) | 2636 | int *open_target_sessions) |
2636 | { | 2637 | { |
2638 | struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc; | ||
2637 | struct ceph_inode_info *ci = ceph_inode(inode); | 2639 | struct ceph_inode_info *ci = ceph_inode(inode); |
2638 | int mds = session->s_mds; | 2640 | int mds = session->s_mds; |
2639 | unsigned mseq = le32_to_cpu(ex->migrate_seq); | 2641 | unsigned mseq = le32_to_cpu(ex->migrate_seq); |
@@ -2670,6 +2672,19 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex, | |||
2670 | * export targets, so that we get the matching IMPORT | 2672 | * export targets, so that we get the matching IMPORT |
2671 | */ | 2673 | */ |
2672 | *open_target_sessions = 1; | 2674 | *open_target_sessions = 1; |
2675 | |||
2676 | /* | ||
2677 | * we can't flush dirty caps that we've seen the | ||
2678 | * EXPORT but no IMPORT for | ||
2679 | */ | ||
2680 | spin_lock(&mdsc->cap_dirty_lock); | ||
2681 | if (!list_empty(&ci->i_dirty_item)) { | ||
2682 | dout(" moving %p to cap_dirty_migrating\n", | ||
2683 | inode); | ||
2684 | list_move(&ci->i_dirty_item, | ||
2685 | &mdsc->cap_dirty_migrating); | ||
2686 | } | ||
2687 | spin_unlock(&mdsc->cap_dirty_lock); | ||
2673 | } | 2688 | } |
2674 | __ceph_remove_cap(cap); | 2689 | __ceph_remove_cap(cap); |
2675 | } | 2690 | } |
@@ -2707,6 +2722,13 @@ static void handle_cap_import(struct ceph_mds_client *mdsc, | |||
2707 | ci->i_cap_exporting_issued = 0; | 2722 | ci->i_cap_exporting_issued = 0; |
2708 | ci->i_cap_exporting_mseq = 0; | 2723 | ci->i_cap_exporting_mseq = 0; |
2709 | ci->i_cap_exporting_mds = -1; | 2724 | ci->i_cap_exporting_mds = -1; |
2725 | |||
2726 | spin_lock(&mdsc->cap_dirty_lock); | ||
2727 | if (!list_empty(&ci->i_dirty_item)) { | ||
2728 | dout(" moving %p back to cap_dirty\n", inode); | ||
2729 | list_move(&ci->i_dirty_item, &mdsc->cap_dirty); | ||
2730 | } | ||
2731 | spin_unlock(&mdsc->cap_dirty_lock); | ||
2710 | } else { | 2732 | } else { |
2711 | dout("handle_cap_import inode %p ci %p mds%d mseq %d\n", | 2733 | dout("handle_cap_import inode %p ci %p mds%d mseq %d\n", |
2712 | inode, ci, mds, mseq); | 2734 | inode, ci, mds, mseq); |
@@ -2910,38 +2932,16 @@ void ceph_check_delayed_caps(struct ceph_mds_client *mdsc) | |||
2910 | */ | 2932 | */ |
2911 | void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc) | 2933 | void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc) |
2912 | { | 2934 | { |
2913 | struct ceph_inode_info *ci, *nci = NULL; | 2935 | struct ceph_inode_info *ci; |
2914 | struct inode *inode, *ninode = NULL; | 2936 | struct inode *inode; |
2915 | struct list_head *p, *n; | ||
2916 | 2937 | ||
2917 | dout("flush_dirty_caps\n"); | 2938 | dout("flush_dirty_caps\n"); |
2918 | spin_lock(&mdsc->cap_dirty_lock); | 2939 | spin_lock(&mdsc->cap_dirty_lock); |
2919 | list_for_each_safe(p, n, &mdsc->cap_dirty) { | 2940 | while (!list_empty(&mdsc->cap_dirty)) { |
2920 | if (nci) { | 2941 | ci = list_first_entry(&mdsc->cap_dirty, struct ceph_inode_info, |
2921 | ci = nci; | 2942 | i_dirty_item); |
2922 | inode = ninode; | 2943 | inode = igrab(&ci->vfs_inode); |
2923 | ci->i_ceph_flags &= ~CEPH_I_NOFLUSH; | 2944 | dout("flush_dirty_caps %p\n", inode); |
2924 | dout("flush_dirty_caps inode %p (was next inode)\n", | ||
2925 | inode); | ||
2926 | } else { | ||
2927 | ci = list_entry(p, struct ceph_inode_info, | ||
2928 | i_dirty_item); | ||
2929 | inode = igrab(&ci->vfs_inode); | ||
2930 | BUG_ON(!inode); | ||
2931 | dout("flush_dirty_caps inode %p\n", inode); | ||
2932 | } | ||
2933 | if (n != &mdsc->cap_dirty) { | ||
2934 | nci = list_entry(n, struct ceph_inode_info, | ||
2935 | i_dirty_item); | ||
2936 | ninode = igrab(&nci->vfs_inode); | ||
2937 | BUG_ON(!ninode); | ||
2938 | nci->i_ceph_flags |= CEPH_I_NOFLUSH; | ||
2939 | dout("flush_dirty_caps next inode %p, noflush\n", | ||
2940 | ninode); | ||
2941 | } else { | ||
2942 | nci = NULL; | ||
2943 | ninode = NULL; | ||
2944 | } | ||
2945 | spin_unlock(&mdsc->cap_dirty_lock); | 2945 | spin_unlock(&mdsc->cap_dirty_lock); |
2946 | if (inode) { | 2946 | if (inode) { |
2947 | ceph_check_caps(ci, CHECK_CAPS_NODELAY|CHECK_CAPS_FLUSH, | 2947 | ceph_check_caps(ci, CHECK_CAPS_NODELAY|CHECK_CAPS_FLUSH, |
@@ -2951,6 +2951,7 @@ void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc) | |||
2951 | spin_lock(&mdsc->cap_dirty_lock); | 2951 | spin_lock(&mdsc->cap_dirty_lock); |
2952 | } | 2952 | } |
2953 | spin_unlock(&mdsc->cap_dirty_lock); | 2953 | spin_unlock(&mdsc->cap_dirty_lock); |
2954 | dout("flush_dirty_caps done\n"); | ||
2954 | } | 2955 | } |
2955 | 2956 | ||
2956 | /* | 2957 | /* |
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 1a867a3601ae..33729e822bb9 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -360,7 +360,7 @@ more: | |||
360 | rinfo = &fi->last_readdir->r_reply_info; | 360 | rinfo = &fi->last_readdir->r_reply_info; |
361 | dout("readdir frag %x num %d off %d chunkoff %d\n", frag, | 361 | dout("readdir frag %x num %d off %d chunkoff %d\n", frag, |
362 | rinfo->dir_nr, off, fi->offset); | 362 | rinfo->dir_nr, off, fi->offset); |
363 | while (off - fi->offset >= 0 && off - fi->offset < rinfo->dir_nr) { | 363 | while (off >= fi->offset && off - fi->offset < rinfo->dir_nr) { |
364 | u64 pos = ceph_make_fpos(frag, off); | 364 | u64 pos = ceph_make_fpos(frag, off); |
365 | struct ceph_mds_reply_inode *in = | 365 | struct ceph_mds_reply_inode *in = |
366 | rinfo->dir_in[off - fi->offset].in; | 366 | rinfo->dir_in[off - fi->offset].in; |
@@ -1066,16 +1066,17 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size, | |||
1066 | struct inode *inode = file->f_dentry->d_inode; | 1066 | struct inode *inode = file->f_dentry->d_inode; |
1067 | struct ceph_inode_info *ci = ceph_inode(inode); | 1067 | struct ceph_inode_info *ci = ceph_inode(inode); |
1068 | int left; | 1068 | int left; |
1069 | const int bufsize = 1024; | ||
1069 | 1070 | ||
1070 | if (!ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb), DIRSTAT)) | 1071 | if (!ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb), DIRSTAT)) |
1071 | return -EISDIR; | 1072 | return -EISDIR; |
1072 | 1073 | ||
1073 | if (!cf->dir_info) { | 1074 | if (!cf->dir_info) { |
1074 | cf->dir_info = kmalloc(1024, GFP_NOFS); | 1075 | cf->dir_info = kmalloc(bufsize, GFP_NOFS); |
1075 | if (!cf->dir_info) | 1076 | if (!cf->dir_info) |
1076 | return -ENOMEM; | 1077 | return -ENOMEM; |
1077 | cf->dir_info_len = | 1078 | cf->dir_info_len = |
1078 | sprintf(cf->dir_info, | 1079 | snprintf(cf->dir_info, bufsize, |
1079 | "entries: %20lld\n" | 1080 | "entries: %20lld\n" |
1080 | " files: %20lld\n" | 1081 | " files: %20lld\n" |
1081 | " subdirs: %20lld\n" | 1082 | " subdirs: %20lld\n" |
diff --git a/fs/ceph/export.c b/fs/ceph/export.c index e41056174bf8..a610d3d67488 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c | |||
@@ -86,6 +86,7 @@ static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len, | |||
86 | static struct dentry *__fh_to_dentry(struct super_block *sb, | 86 | static struct dentry *__fh_to_dentry(struct super_block *sb, |
87 | struct ceph_nfs_fh *fh) | 87 | struct ceph_nfs_fh *fh) |
88 | { | 88 | { |
89 | struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc; | ||
89 | struct inode *inode; | 90 | struct inode *inode; |
90 | struct dentry *dentry; | 91 | struct dentry *dentry; |
91 | struct ceph_vino vino; | 92 | struct ceph_vino vino; |
@@ -95,8 +96,24 @@ static struct dentry *__fh_to_dentry(struct super_block *sb, | |||
95 | vino.ino = fh->ino; | 96 | vino.ino = fh->ino; |
96 | vino.snap = CEPH_NOSNAP; | 97 | vino.snap = CEPH_NOSNAP; |
97 | inode = ceph_find_inode(sb, vino); | 98 | inode = ceph_find_inode(sb, vino); |
98 | if (!inode) | 99 | if (!inode) { |
99 | return ERR_PTR(-ESTALE); | 100 | struct ceph_mds_request *req; |
101 | |||
102 | req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO, | ||
103 | USE_ANY_MDS); | ||
104 | if (IS_ERR(req)) | ||
105 | return ERR_CAST(req); | ||
106 | |||
107 | req->r_ino1 = vino; | ||
108 | req->r_num_caps = 1; | ||
109 | err = ceph_mdsc_do_request(mdsc, NULL, req); | ||
110 | inode = req->r_target_inode; | ||
111 | if (inode) | ||
112 | igrab(inode); | ||
113 | ceph_mdsc_put_request(req); | ||
114 | if (!inode) | ||
115 | return ERR_PTR(-ESTALE); | ||
116 | } | ||
100 | 117 | ||
101 | dentry = d_obtain_alias(inode); | 118 | dentry = d_obtain_alias(inode); |
102 | if (IS_ERR(dentry)) { | 119 | if (IS_ERR(dentry)) { |
@@ -148,8 +165,10 @@ static struct dentry *__cfh_to_dentry(struct super_block *sb, | |||
148 | snprintf(req->r_path2, 16, "%d", cfh->parent_name_hash); | 165 | snprintf(req->r_path2, 16, "%d", cfh->parent_name_hash); |
149 | req->r_num_caps = 1; | 166 | req->r_num_caps = 1; |
150 | err = ceph_mdsc_do_request(mdsc, NULL, req); | 167 | err = ceph_mdsc_do_request(mdsc, NULL, req); |
168 | inode = req->r_target_inode; | ||
169 | if (inode) | ||
170 | igrab(inode); | ||
151 | ceph_mdsc_put_request(req); | 171 | ceph_mdsc_put_request(req); |
152 | inode = ceph_find_inode(sb, vino); | ||
153 | if (!inode) | 172 | if (!inode) |
154 | return ERR_PTR(err ? err : -ESTALE); | 173 | return ERR_PTR(err ? err : -ESTALE); |
155 | } | 174 | } |
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 159b512d5a27..203252d88d9f 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c | |||
@@ -734,9 +734,12 @@ retry_snap: | |||
734 | } | 734 | } |
735 | } | 735 | } |
736 | if (ret >= 0) { | 736 | if (ret >= 0) { |
737 | int dirty; | ||
737 | spin_lock(&inode->i_lock); | 738 | spin_lock(&inode->i_lock); |
738 | __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR); | 739 | dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR); |
739 | spin_unlock(&inode->i_lock); | 740 | spin_unlock(&inode->i_lock); |
741 | if (dirty) | ||
742 | __mark_inode_dirty(inode, dirty); | ||
740 | } | 743 | } |
741 | 744 | ||
742 | out: | 745 | out: |
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index b54c97da1c43..70b6a4839c38 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
@@ -355,6 +355,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb) | |||
355 | ci->i_rd_ref = 0; | 355 | ci->i_rd_ref = 0; |
356 | ci->i_rdcache_ref = 0; | 356 | ci->i_rdcache_ref = 0; |
357 | ci->i_wr_ref = 0; | 357 | ci->i_wr_ref = 0; |
358 | ci->i_wb_ref = 0; | ||
358 | ci->i_wrbuffer_ref = 0; | 359 | ci->i_wrbuffer_ref = 0; |
359 | ci->i_wrbuffer_ref_head = 0; | 360 | ci->i_wrbuffer_ref_head = 0; |
360 | ci->i_shared_gen = 0; | 361 | ci->i_shared_gen = 0; |
@@ -1567,6 +1568,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) | |||
1567 | int release = 0, dirtied = 0; | 1568 | int release = 0, dirtied = 0; |
1568 | int mask = 0; | 1569 | int mask = 0; |
1569 | int err = 0; | 1570 | int err = 0; |
1571 | int inode_dirty_flags = 0; | ||
1570 | 1572 | ||
1571 | if (ceph_snap(inode) != CEPH_NOSNAP) | 1573 | if (ceph_snap(inode) != CEPH_NOSNAP) |
1572 | return -EROFS; | 1574 | return -EROFS; |
@@ -1725,13 +1727,16 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) | |||
1725 | dout("setattr %p ATTR_FILE ... hrm!\n", inode); | 1727 | dout("setattr %p ATTR_FILE ... hrm!\n", inode); |
1726 | 1728 | ||
1727 | if (dirtied) { | 1729 | if (dirtied) { |
1728 | __ceph_mark_dirty_caps(ci, dirtied); | 1730 | inode_dirty_flags = __ceph_mark_dirty_caps(ci, dirtied); |
1729 | inode->i_ctime = CURRENT_TIME; | 1731 | inode->i_ctime = CURRENT_TIME; |
1730 | } | 1732 | } |
1731 | 1733 | ||
1732 | release &= issued; | 1734 | release &= issued; |
1733 | spin_unlock(&inode->i_lock); | 1735 | spin_unlock(&inode->i_lock); |
1734 | 1736 | ||
1737 | if (inode_dirty_flags) | ||
1738 | __mark_inode_dirty(inode, inode_dirty_flags); | ||
1739 | |||
1735 | if (mask) { | 1740 | if (mask) { |
1736 | req->r_inode = igrab(inode); | 1741 | req->r_inode = igrab(inode); |
1737 | req->r_inode_drop = release; | 1742 | req->r_inode_drop = release; |
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index f60b07b0feb0..79743d146be6 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
@@ -578,6 +578,7 @@ static void __register_request(struct ceph_mds_client *mdsc, | |||
578 | if (dir) { | 578 | if (dir) { |
579 | struct ceph_inode_info *ci = ceph_inode(dir); | 579 | struct ceph_inode_info *ci = ceph_inode(dir); |
580 | 580 | ||
581 | ihold(dir); | ||
581 | spin_lock(&ci->i_unsafe_lock); | 582 | spin_lock(&ci->i_unsafe_lock); |
582 | req->r_unsafe_dir = dir; | 583 | req->r_unsafe_dir = dir; |
583 | list_add_tail(&req->r_unsafe_dir_item, &ci->i_unsafe_dirops); | 584 | list_add_tail(&req->r_unsafe_dir_item, &ci->i_unsafe_dirops); |
@@ -598,6 +599,9 @@ static void __unregister_request(struct ceph_mds_client *mdsc, | |||
598 | spin_lock(&ci->i_unsafe_lock); | 599 | spin_lock(&ci->i_unsafe_lock); |
599 | list_del_init(&req->r_unsafe_dir_item); | 600 | list_del_init(&req->r_unsafe_dir_item); |
600 | spin_unlock(&ci->i_unsafe_lock); | 601 | spin_unlock(&ci->i_unsafe_lock); |
602 | |||
603 | iput(req->r_unsafe_dir); | ||
604 | req->r_unsafe_dir = NULL; | ||
601 | } | 605 | } |
602 | 606 | ||
603 | ceph_mdsc_put_request(req); | 607 | ceph_mdsc_put_request(req); |
@@ -2691,7 +2695,6 @@ static void handle_lease(struct ceph_mds_client *mdsc, | |||
2691 | { | 2695 | { |
2692 | struct super_block *sb = mdsc->fsc->sb; | 2696 | struct super_block *sb = mdsc->fsc->sb; |
2693 | struct inode *inode; | 2697 | struct inode *inode; |
2694 | struct ceph_inode_info *ci; | ||
2695 | struct dentry *parent, *dentry; | 2698 | struct dentry *parent, *dentry; |
2696 | struct ceph_dentry_info *di; | 2699 | struct ceph_dentry_info *di; |
2697 | int mds = session->s_mds; | 2700 | int mds = session->s_mds; |
@@ -2728,7 +2731,6 @@ static void handle_lease(struct ceph_mds_client *mdsc, | |||
2728 | dout("handle_lease no inode %llx\n", vino.ino); | 2731 | dout("handle_lease no inode %llx\n", vino.ino); |
2729 | goto release; | 2732 | goto release; |
2730 | } | 2733 | } |
2731 | ci = ceph_inode(inode); | ||
2732 | 2734 | ||
2733 | /* dentry */ | 2735 | /* dentry */ |
2734 | parent = d_find_alias(inode); | 2736 | parent = d_find_alias(inode); |
@@ -3002,6 +3004,7 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc) | |||
3002 | spin_lock_init(&mdsc->snap_flush_lock); | 3004 | spin_lock_init(&mdsc->snap_flush_lock); |
3003 | mdsc->cap_flush_seq = 0; | 3005 | mdsc->cap_flush_seq = 0; |
3004 | INIT_LIST_HEAD(&mdsc->cap_dirty); | 3006 | INIT_LIST_HEAD(&mdsc->cap_dirty); |
3007 | INIT_LIST_HEAD(&mdsc->cap_dirty_migrating); | ||
3005 | mdsc->num_cap_flushing = 0; | 3008 | mdsc->num_cap_flushing = 0; |
3006 | spin_lock_init(&mdsc->cap_dirty_lock); | 3009 | spin_lock_init(&mdsc->cap_dirty_lock); |
3007 | init_waitqueue_head(&mdsc->cap_flushing_wq); | 3010 | init_waitqueue_head(&mdsc->cap_flushing_wq); |
@@ -3304,8 +3307,8 @@ static void con_put(struct ceph_connection *con) | |||
3304 | { | 3307 | { |
3305 | struct ceph_mds_session *s = con->private; | 3308 | struct ceph_mds_session *s = con->private; |
3306 | 3309 | ||
3310 | dout("mdsc con_put %p (%d)\n", s, atomic_read(&s->s_ref) - 1); | ||
3307 | ceph_put_mds_session(s); | 3311 | ceph_put_mds_session(s); |
3308 | dout("mdsc con_put %p (%d)\n", s, atomic_read(&s->s_ref)); | ||
3309 | } | 3312 | } |
3310 | 3313 | ||
3311 | /* | 3314 | /* |
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 4e3a9cc0bba6..7d8a0d662d56 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h | |||
@@ -278,6 +278,7 @@ struct ceph_mds_client { | |||
278 | 278 | ||
279 | u64 cap_flush_seq; | 279 | u64 cap_flush_seq; |
280 | struct list_head cap_dirty; /* inodes with dirty caps */ | 280 | struct list_head cap_dirty; /* inodes with dirty caps */ |
281 | struct list_head cap_dirty_migrating; /* ...that are migration... */ | ||
281 | int num_cap_flushing; /* # caps we are flushing */ | 282 | int num_cap_flushing; /* # caps we are flushing */ |
282 | spinlock_t cap_dirty_lock; /* protects above items */ | 283 | spinlock_t cap_dirty_lock; /* protects above items */ |
283 | wait_queue_head_t cap_flushing_wq; | 284 | wait_queue_head_t cap_flushing_wq; |
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index e86ec1155f8f..24067d68a554 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c | |||
@@ -206,7 +206,7 @@ void ceph_put_snap_realm(struct ceph_mds_client *mdsc, | |||
206 | up_write(&mdsc->snap_rwsem); | 206 | up_write(&mdsc->snap_rwsem); |
207 | } else { | 207 | } else { |
208 | spin_lock(&mdsc->snap_empty_lock); | 208 | spin_lock(&mdsc->snap_empty_lock); |
209 | list_add(&mdsc->snap_empty, &realm->empty_item); | 209 | list_add(&realm->empty_item, &mdsc->snap_empty); |
210 | spin_unlock(&mdsc->snap_empty_lock); | 210 | spin_unlock(&mdsc->snap_empty_lock); |
211 | } | 211 | } |
212 | } | 212 | } |
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 619fe719968f..f5cabefa98dc 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h | |||
@@ -293,7 +293,7 @@ struct ceph_inode_info { | |||
293 | 293 | ||
294 | /* held references to caps */ | 294 | /* held references to caps */ |
295 | int i_pin_ref; | 295 | int i_pin_ref; |
296 | int i_rd_ref, i_rdcache_ref, i_wr_ref; | 296 | int i_rd_ref, i_rdcache_ref, i_wr_ref, i_wb_ref; |
297 | int i_wrbuffer_ref, i_wrbuffer_ref_head; | 297 | int i_wrbuffer_ref, i_wrbuffer_ref_head; |
298 | u32 i_shared_gen; /* increment each time we get FILE_SHARED */ | 298 | u32 i_shared_gen; /* increment each time we get FILE_SHARED */ |
299 | u32 i_rdcache_gen; /* incremented each time we get FILE_CACHE. */ | 299 | u32 i_rdcache_gen; /* incremented each time we get FILE_CACHE. */ |
@@ -506,7 +506,7 @@ static inline int __ceph_caps_dirty(struct ceph_inode_info *ci) | |||
506 | { | 506 | { |
507 | return ci->i_dirty_caps | ci->i_flushing_caps; | 507 | return ci->i_dirty_caps | ci->i_flushing_caps; |
508 | } | 508 | } |
509 | extern void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask); | 509 | extern int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask); |
510 | 510 | ||
511 | extern int ceph_caps_revoking(struct ceph_inode_info *ci, int mask); | 511 | extern int ceph_caps_revoking(struct ceph_inode_info *ci, int mask); |
512 | extern int __ceph_caps_used(struct ceph_inode_info *ci); | 512 | extern int __ceph_caps_used(struct ceph_inode_info *ci); |
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index 8c9eba6ef9df..f2b628696180 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c | |||
@@ -703,6 +703,7 @@ int ceph_setxattr(struct dentry *dentry, const char *name, | |||
703 | struct ceph_inode_xattr *xattr = NULL; | 703 | struct ceph_inode_xattr *xattr = NULL; |
704 | int issued; | 704 | int issued; |
705 | int required_blob_size; | 705 | int required_blob_size; |
706 | int dirty; | ||
706 | 707 | ||
707 | if (ceph_snap(inode) != CEPH_NOSNAP) | 708 | if (ceph_snap(inode) != CEPH_NOSNAP) |
708 | return -EROFS; | 709 | return -EROFS; |
@@ -763,11 +764,12 @@ retry: | |||
763 | dout("setxattr %p issued %s\n", inode, ceph_cap_string(issued)); | 764 | dout("setxattr %p issued %s\n", inode, ceph_cap_string(issued)); |
764 | err = __set_xattr(ci, newname, name_len, newval, | 765 | err = __set_xattr(ci, newname, name_len, newval, |
765 | val_len, 1, 1, 1, &xattr); | 766 | val_len, 1, 1, 1, &xattr); |
766 | __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); | 767 | dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); |
767 | ci->i_xattrs.dirty = true; | 768 | ci->i_xattrs.dirty = true; |
768 | inode->i_ctime = CURRENT_TIME; | 769 | inode->i_ctime = CURRENT_TIME; |
769 | spin_unlock(&inode->i_lock); | 770 | spin_unlock(&inode->i_lock); |
770 | 771 | if (dirty) | |
772 | __mark_inode_dirty(inode, dirty); | ||
771 | return err; | 773 | return err; |
772 | 774 | ||
773 | do_sync: | 775 | do_sync: |
@@ -810,6 +812,7 @@ int ceph_removexattr(struct dentry *dentry, const char *name) | |||
810 | struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode); | 812 | struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode); |
811 | int issued; | 813 | int issued; |
812 | int err; | 814 | int err; |
815 | int dirty; | ||
813 | 816 | ||
814 | if (ceph_snap(inode) != CEPH_NOSNAP) | 817 | if (ceph_snap(inode) != CEPH_NOSNAP) |
815 | return -EROFS; | 818 | return -EROFS; |
@@ -833,12 +836,13 @@ int ceph_removexattr(struct dentry *dentry, const char *name) | |||
833 | goto do_sync; | 836 | goto do_sync; |
834 | 837 | ||
835 | err = __remove_xattr_by_name(ceph_inode(inode), name); | 838 | err = __remove_xattr_by_name(ceph_inode(inode), name); |
836 | __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); | 839 | dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); |
837 | ci->i_xattrs.dirty = true; | 840 | ci->i_xattrs.dirty = true; |
838 | inode->i_ctime = CURRENT_TIME; | 841 | inode->i_ctime = CURRENT_TIME; |
839 | 842 | ||
840 | spin_unlock(&inode->i_lock); | 843 | spin_unlock(&inode->i_lock); |
841 | 844 | if (dirty) | |
845 | __mark_inode_dirty(inode, dirty); | ||
842 | return err; | 846 | return err; |
843 | do_sync: | 847 | do_sync: |
844 | spin_unlock(&inode->i_lock); | 848 | spin_unlock(&inode->i_lock); |