diff options
author | Sage Weil <sage@newdream.net> | 2009-10-14 17:27:38 -0400 |
---|---|---|
committer | Sage Weil <sage@newdream.net> | 2009-10-15 21:14:35 -0400 |
commit | afcdaea3f2a78ce4873bd7e98a6d603bda23d167 (patch) | |
tree | 08defc298e2c27816d70bd41c8c3ecc80a82ba79 /fs/ceph | |
parent | cdc35f96277314bbfeefd0505410cabd69aebd8d (diff) |
ceph: flush dirty caps via the cap_dirty list
Previously we were flushing dirty caps by passing an extra flag
when traversing the delayed caps list. Besides being a bit ugly,
that can also miss caps that are dirty but didn't result in a
cap requeue: notably, mark_caps_dirty().
Separate the flushing into a separate helper, and traverse the
cap_dirty list.
This also brings i_dirty_item in line with i_dirty_caps: we are
on the list IFF caps != 0. We carry an inode ref IFF
dirty_caps|flushing_caps != 0.
Lose the unused return value from __ceph_mark_caps_dirty().
Signed-off-by: Sage Weil <sage@newdream.net>
Diffstat (limited to 'fs/ceph')
-rw-r--r-- | fs/ceph/caps.c | 76 | ||||
-rw-r--r-- | fs/ceph/mds_client.c | 6 | ||||
-rw-r--r-- | fs/ceph/super.h | 6 |
3 files changed, 59 insertions, 29 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 111439d883d2..40b8d3471244 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
@@ -997,7 +997,7 @@ void ceph_queue_caps_release(struct inode *inode) | |||
997 | if (le32_to_cpu(head->num) == CEPH_CAPS_PER_RELEASE) { | 997 | if (le32_to_cpu(head->num) == CEPH_CAPS_PER_RELEASE) { |
998 | dout(" release msg %p full\n", msg); | 998 | dout(" release msg %p full\n", msg); |
999 | list_move_tail(&msg->list_head, | 999 | list_move_tail(&msg->list_head, |
1000 | &session->s_cap_releases_done); | 1000 | &session->s_cap_releases_done); |
1001 | } else { | 1001 | } else { |
1002 | dout(" release msg %p at %d/%d (%d)\n", msg, | 1002 | dout(" release msg %p at %d/%d (%d)\n", msg, |
1003 | (int)le32_to_cpu(head->num), | 1003 | (int)le32_to_cpu(head->num), |
@@ -1292,14 +1292,20 @@ static int __mark_caps_flushing(struct inode *inode, | |||
1292 | ceph_cap_string(ci->i_flushing_caps | flushing)); | 1292 | ceph_cap_string(ci->i_flushing_caps | flushing)); |
1293 | ci->i_flushing_caps |= flushing; | 1293 | ci->i_flushing_caps |= flushing; |
1294 | ci->i_dirty_caps = 0; | 1294 | ci->i_dirty_caps = 0; |
1295 | dout(" inode %p now !dirty\n", inode); | ||
1295 | 1296 | ||
1296 | spin_lock(&mdsc->cap_dirty_lock); | 1297 | spin_lock(&mdsc->cap_dirty_lock); |
1298 | list_del_init(&ci->i_dirty_item); | ||
1299 | |||
1300 | ci->i_cap_flush_seq = ++mdsc->cap_flush_seq; | ||
1297 | if (list_empty(&ci->i_flushing_item)) { | 1301 | if (list_empty(&ci->i_flushing_item)) { |
1298 | list_del_init(&ci->i_dirty_item); | ||
1299 | list_add_tail(&ci->i_flushing_item, &session->s_cap_flushing); | 1302 | list_add_tail(&ci->i_flushing_item, &session->s_cap_flushing); |
1300 | mdsc->num_cap_flushing++; | 1303 | mdsc->num_cap_flushing++; |
1301 | ci->i_cap_flush_seq = ++mdsc->cap_flush_seq; | 1304 | dout(" inode %p now flushing seq %lld\n", inode, |
1302 | dout(" inode %p now flushing seq %lld\n", &ci->vfs_inode, | 1305 | ci->i_cap_flush_seq); |
1306 | } else { | ||
1307 | list_move_tail(&ci->i_flushing_item, &session->s_cap_flushing); | ||
1308 | dout(" inode %p now flushing (more) seq %lld\n", inode, | ||
1303 | ci->i_cap_flush_seq); | 1309 | ci->i_cap_flush_seq); |
1304 | } | 1310 | } |
1305 | spin_unlock(&mdsc->cap_dirty_lock); | 1311 | spin_unlock(&mdsc->cap_dirty_lock); |
@@ -1555,32 +1561,33 @@ ack: | |||
1555 | * Mark caps dirty. If inode is newly dirty, add to the global dirty | 1561 | * Mark caps dirty. If inode is newly dirty, add to the global dirty |
1556 | * list. | 1562 | * list. |
1557 | */ | 1563 | */ |
1558 | int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) | 1564 | void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) |
1559 | { | 1565 | { |
1560 | struct ceph_mds_client *mdsc = &ceph_client(ci->vfs_inode.i_sb)->mdsc; | 1566 | struct ceph_mds_client *mdsc = &ceph_client(ci->vfs_inode.i_sb)->mdsc; |
1561 | struct inode *inode = &ci->vfs_inode; | 1567 | struct inode *inode = &ci->vfs_inode; |
1562 | int was = __ceph_caps_dirty(ci); | 1568 | int was_dirty = ci->i_dirty_caps; |
1563 | int dirty = 0; | 1569 | int dirty = 0; |
1564 | 1570 | ||
1565 | dout("__mark_dirty_caps %p %s dirty %s -> %s\n", &ci->vfs_inode, | 1571 | dout("__mark_dirty_caps %p %s dirty %s -> %s\n", &ci->vfs_inode, |
1566 | ceph_cap_string(mask), ceph_cap_string(ci->i_dirty_caps), | 1572 | ceph_cap_string(mask), ceph_cap_string(ci->i_dirty_caps), |
1567 | ceph_cap_string(ci->i_dirty_caps | mask)); | 1573 | ceph_cap_string(ci->i_dirty_caps | mask)); |
1568 | ci->i_dirty_caps |= mask; | 1574 | ci->i_dirty_caps |= mask; |
1569 | if (!was) { | 1575 | if (!was_dirty) { |
1570 | dout(" inode %p now dirty\n", &ci->vfs_inode); | 1576 | dout(" inode %p now dirty\n", &ci->vfs_inode); |
1571 | spin_lock(&mdsc->cap_dirty_lock); | 1577 | spin_lock(&mdsc->cap_dirty_lock); |
1572 | list_add(&ci->i_dirty_item, &mdsc->cap_dirty); | 1578 | list_add(&ci->i_dirty_item, &mdsc->cap_dirty); |
1573 | spin_unlock(&mdsc->cap_dirty_lock); | 1579 | spin_unlock(&mdsc->cap_dirty_lock); |
1574 | igrab(inode); | 1580 | if (ci->i_flushing_caps == 0) { |
1575 | dirty |= I_DIRTY_SYNC; | 1581 | igrab(inode); |
1582 | dirty |= I_DIRTY_SYNC; | ||
1583 | } | ||
1576 | } | 1584 | } |
1577 | if ((was & CEPH_CAP_FILE_BUFFER) && | 1585 | if (((was_dirty | ci->i_flushing_caps) & CEPH_CAP_FILE_BUFFER) && |
1578 | (mask & CEPH_CAP_FILE_BUFFER)) | 1586 | (mask & CEPH_CAP_FILE_BUFFER)) |
1579 | dirty |= I_DIRTY_DATASYNC; | 1587 | dirty |= I_DIRTY_DATASYNC; |
1580 | if (dirty) | 1588 | if (dirty) |
1581 | __mark_inode_dirty(inode, dirty); | 1589 | __mark_inode_dirty(inode, dirty); |
1582 | __cap_delay_requeue(mdsc, ci); | 1590 | __cap_delay_requeue(mdsc, ci); |
1583 | return was; | ||
1584 | } | 1591 | } |
1585 | 1592 | ||
1586 | /* | 1593 | /* |
@@ -2327,7 +2334,7 @@ static void handle_cap_flush_ack(struct inode *inode, | |||
2327 | int dirty = le32_to_cpu(m->dirty); | 2334 | int dirty = le32_to_cpu(m->dirty); |
2328 | int cleaned = 0; | 2335 | int cleaned = 0; |
2329 | u64 flush_tid = le64_to_cpu(m->client_tid); | 2336 | u64 flush_tid = le64_to_cpu(m->client_tid); |
2330 | int old_dirty = 0, new_dirty = 0; | 2337 | int drop = 0; |
2331 | int i; | 2338 | int i; |
2332 | 2339 | ||
2333 | for (i = 0; i < CEPH_CAP_BITS; i++) | 2340 | for (i = 0; i < CEPH_CAP_BITS; i++) |
@@ -2344,9 +2351,7 @@ static void handle_cap_flush_ack(struct inode *inode, | |||
2344 | if (ci->i_flushing_caps == (ci->i_flushing_caps & ~cleaned)) | 2351 | if (ci->i_flushing_caps == (ci->i_flushing_caps & ~cleaned)) |
2345 | goto out; | 2352 | goto out; |
2346 | 2353 | ||
2347 | old_dirty = ci->i_dirty_caps | ci->i_flushing_caps; | ||
2348 | ci->i_flushing_caps &= ~cleaned; | 2354 | ci->i_flushing_caps &= ~cleaned; |
2349 | new_dirty = ci->i_dirty_caps | ci->i_flushing_caps; | ||
2350 | 2355 | ||
2351 | spin_lock(&mdsc->cap_dirty_lock); | 2356 | spin_lock(&mdsc->cap_dirty_lock); |
2352 | if (ci->i_flushing_caps == 0) { | 2357 | if (ci->i_flushing_caps == 0) { |
@@ -2360,17 +2365,19 @@ static void handle_cap_flush_ack(struct inode *inode, | |||
2360 | mdsc->num_cap_flushing--; | 2365 | mdsc->num_cap_flushing--; |
2361 | wake_up(&mdsc->cap_flushing_wq); | 2366 | wake_up(&mdsc->cap_flushing_wq); |
2362 | dout(" inode %p now !flushing\n", inode); | 2367 | dout(" inode %p now !flushing\n", inode); |
2363 | } | 2368 | |
2364 | if (old_dirty && !new_dirty) { | 2369 | if (ci->i_dirty_caps == 0) { |
2365 | dout(" inode %p now clean\n", inode); | 2370 | dout(" inode %p now clean\n", inode); |
2366 | list_del_init(&ci->i_dirty_item); | 2371 | BUG_ON(!list_empty(&ci->i_dirty_item)); |
2372 | drop = 1; | ||
2373 | } | ||
2367 | } | 2374 | } |
2368 | spin_unlock(&mdsc->cap_dirty_lock); | 2375 | spin_unlock(&mdsc->cap_dirty_lock); |
2369 | wake_up(&ci->i_cap_wq); | 2376 | wake_up(&ci->i_cap_wq); |
2370 | 2377 | ||
2371 | out: | 2378 | out: |
2372 | spin_unlock(&inode->i_lock); | 2379 | spin_unlock(&inode->i_lock); |
2373 | if (old_dirty && !new_dirty) | 2380 | if (drop) |
2374 | iput(inode); | 2381 | iput(inode); |
2375 | } | 2382 | } |
2376 | 2383 | ||
@@ -2676,14 +2683,11 @@ bad: | |||
2676 | /* | 2683 | /* |
2677 | * Delayed work handler to process end of delayed cap release LRU list. | 2684 | * Delayed work handler to process end of delayed cap release LRU list. |
2678 | */ | 2685 | */ |
2679 | void ceph_check_delayed_caps(struct ceph_mds_client *mdsc, int flushdirty) | 2686 | void ceph_check_delayed_caps(struct ceph_mds_client *mdsc) |
2680 | { | 2687 | { |
2681 | struct ceph_inode_info *ci; | 2688 | struct ceph_inode_info *ci; |
2682 | int flags = CHECK_CAPS_NODELAY; | 2689 | int flags = CHECK_CAPS_NODELAY; |
2683 | 2690 | ||
2684 | if (flushdirty) | ||
2685 | flags |= CHECK_CAPS_FLUSH; | ||
2686 | |||
2687 | dout("check_delayed_caps\n"); | 2691 | dout("check_delayed_caps\n"); |
2688 | while (1) { | 2692 | while (1) { |
2689 | spin_lock(&mdsc->cap_delay_lock); | 2693 | spin_lock(&mdsc->cap_delay_lock); |
@@ -2704,6 +2708,32 @@ void ceph_check_delayed_caps(struct ceph_mds_client *mdsc, int flushdirty) | |||
2704 | } | 2708 | } |
2705 | 2709 | ||
2706 | /* | 2710 | /* |
2711 | * Flush all dirty caps to the mds | ||
2712 | */ | ||
2713 | void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc) | ||
2714 | { | ||
2715 | struct ceph_inode_info *ci; | ||
2716 | struct inode *inode; | ||
2717 | |||
2718 | dout("flush_dirty_caps\n"); | ||
2719 | spin_lock(&mdsc->cap_dirty_lock); | ||
2720 | while (!list_empty(&mdsc->cap_dirty)) { | ||
2721 | ci = list_first_entry(&mdsc->cap_dirty, | ||
2722 | struct ceph_inode_info, | ||
2723 | i_dirty_item); | ||
2724 | inode = igrab(&ci->vfs_inode); | ||
2725 | spin_unlock(&mdsc->cap_dirty_lock); | ||
2726 | if (inode) { | ||
2727 | ceph_check_caps(ci, CHECK_CAPS_NODELAY|CHECK_CAPS_FLUSH, | ||
2728 | NULL); | ||
2729 | iput(inode); | ||
2730 | } | ||
2731 | spin_lock(&mdsc->cap_dirty_lock); | ||
2732 | } | ||
2733 | spin_unlock(&mdsc->cap_dirty_lock); | ||
2734 | } | ||
2735 | |||
2736 | /* | ||
2707 | * Drop open file reference. If we were the last open file, | 2737 | * Drop open file reference. If we were the last open file, |
2708 | * we may need to release capabilities to the MDS (or schedule | 2738 | * we may need to release capabilities to the MDS (or schedule |
2709 | * their delayed release). | 2739 | * their delayed release). |
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 2b19da31a8b3..12d66c0572ac 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
@@ -2504,7 +2504,7 @@ static void delayed_work(struct work_struct *work) | |||
2504 | int renew_caps; | 2504 | int renew_caps; |
2505 | 2505 | ||
2506 | dout("mdsc delayed_work\n"); | 2506 | dout("mdsc delayed_work\n"); |
2507 | ceph_check_delayed_caps(mdsc, 0); | 2507 | ceph_check_delayed_caps(mdsc); |
2508 | 2508 | ||
2509 | mutex_lock(&mdsc->mutex); | 2509 | mutex_lock(&mdsc->mutex); |
2510 | renew_interval = mdsc->mdsmap->m_session_timeout >> 2; | 2510 | renew_interval = mdsc->mdsmap->m_session_timeout >> 2; |
@@ -2627,7 +2627,7 @@ void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc) | |||
2627 | mdsc->stopping = 1; | 2627 | mdsc->stopping = 1; |
2628 | 2628 | ||
2629 | drop_leases(mdsc); | 2629 | drop_leases(mdsc); |
2630 | ceph_check_delayed_caps(mdsc, 1); | 2630 | ceph_flush_dirty_caps(mdsc); |
2631 | wait_requests(mdsc); | 2631 | wait_requests(mdsc); |
2632 | } | 2632 | } |
2633 | 2633 | ||
@@ -2677,7 +2677,7 @@ void ceph_mdsc_sync(struct ceph_mds_client *mdsc) | |||
2677 | mutex_unlock(&mdsc->mutex); | 2677 | mutex_unlock(&mdsc->mutex); |
2678 | dout("sync want tid %lld flush_seq %lld\n", want_tid, want_flush); | 2678 | dout("sync want tid %lld flush_seq %lld\n", want_tid, want_flush); |
2679 | 2679 | ||
2680 | ceph_check_delayed_caps(mdsc, 1); | 2680 | ceph_flush_dirty_caps(mdsc); |
2681 | 2681 | ||
2682 | wait_unsafe_requests(mdsc, want_tid); | 2682 | wait_unsafe_requests(mdsc, want_tid); |
2683 | wait_event(mdsc->cap_flushing_wq, check_cap_flush(mdsc, want_flush)); | 2683 | wait_event(mdsc->cap_flushing_wq, check_cap_flush(mdsc, want_flush)); |
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index cfd39ef4023e..0bbf58ab607e 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h | |||
@@ -524,7 +524,7 @@ static inline int __ceph_caps_dirty(struct ceph_inode_info *ci) | |||
524 | { | 524 | { |
525 | return ci->i_dirty_caps | ci->i_flushing_caps; | 525 | return ci->i_dirty_caps | ci->i_flushing_caps; |
526 | } | 526 | } |
527 | extern int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask); | 527 | extern void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask); |
528 | 528 | ||
529 | extern int ceph_caps_revoking(struct ceph_inode_info *ci, int mask); | 529 | extern int ceph_caps_revoking(struct ceph_inode_info *ci, int mask); |
530 | extern int __ceph_caps_used(struct ceph_inode_info *ci); | 530 | extern int __ceph_caps_used(struct ceph_inode_info *ci); |
@@ -814,8 +814,8 @@ extern void __ceph_flush_snaps(struct ceph_inode_info *ci, | |||
814 | struct ceph_mds_session **psession); | 814 | struct ceph_mds_session **psession); |
815 | extern void ceph_check_caps(struct ceph_inode_info *ci, int flags, | 815 | extern void ceph_check_caps(struct ceph_inode_info *ci, int flags, |
816 | struct ceph_mds_session *session); | 816 | struct ceph_mds_session *session); |
817 | extern void ceph_check_delayed_caps(struct ceph_mds_client *mdsc, | 817 | extern void ceph_check_delayed_caps(struct ceph_mds_client *mdsc); |
818 | int flushdirty); | 818 | extern void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc); |
819 | 819 | ||
820 | extern int ceph_encode_inode_release(void **p, struct inode *inode, | 820 | extern int ceph_encode_inode_release(void **p, struct inode *inode, |
821 | int mds, int drop, int unless, int force); | 821 | int mds, int drop, int unless, int force); |