aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ceph
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ceph')
-rw-r--r--fs/ceph/addr.c12
-rw-r--r--fs/ceph/caps.c91
-rw-r--r--fs/ceph/dir.c7
-rw-r--r--fs/ceph/export.c25
-rw-r--r--fs/ceph/file.c5
-rw-r--r--fs/ceph/inode.c7
-rw-r--r--fs/ceph/mds_client.c9
-rw-r--r--fs/ceph/mds_client.h1
-rw-r--r--fs/ceph/snap.c2
-rw-r--r--fs/ceph/super.h4
-rw-r--r--fs/ceph/xattr.c12
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:
873out: 881out:
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 */
1337void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) 1339int __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 */
2911void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc) 2933void 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,
86static struct dentry *__fh_to_dentry(struct super_block *sb, 86static 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
742out: 745out:
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}
509extern void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask); 509extern int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask);
510 510
511extern int ceph_caps_revoking(struct ceph_inode_info *ci, int mask); 511extern int ceph_caps_revoking(struct ceph_inode_info *ci, int mask);
512extern int __ceph_caps_used(struct ceph_inode_info *ci); 512extern 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
773do_sync: 775do_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;
843do_sync: 847do_sync:
844 spin_unlock(&inode->i_lock); 848 spin_unlock(&inode->i_lock);