diff options
Diffstat (limited to 'fs/ceph/mds_client.c')
| -rw-r--r-- | fs/ceph/mds_client.c | 101 |
1 files changed, 63 insertions, 38 deletions
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index a75ddbf9fe37..f091b1351786 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
| @@ -560,6 +560,13 @@ static void __unregister_request(struct ceph_mds_client *mdsc, | |||
| 560 | * | 560 | * |
| 561 | * Called under mdsc->mutex. | 561 | * Called under mdsc->mutex. |
| 562 | */ | 562 | */ |
| 563 | struct dentry *get_nonsnap_parent(struct dentry *dentry) | ||
| 564 | { | ||
| 565 | while (!IS_ROOT(dentry) && ceph_snap(dentry->d_inode) != CEPH_NOSNAP) | ||
| 566 | dentry = dentry->d_parent; | ||
| 567 | return dentry; | ||
| 568 | } | ||
| 569 | |||
| 563 | static int __choose_mds(struct ceph_mds_client *mdsc, | 570 | static int __choose_mds(struct ceph_mds_client *mdsc, |
| 564 | struct ceph_mds_request *req) | 571 | struct ceph_mds_request *req) |
| 565 | { | 572 | { |
| @@ -590,14 +597,29 @@ static int __choose_mds(struct ceph_mds_client *mdsc, | |||
| 590 | if (req->r_inode) { | 597 | if (req->r_inode) { |
| 591 | inode = req->r_inode; | 598 | inode = req->r_inode; |
| 592 | } else if (req->r_dentry) { | 599 | } else if (req->r_dentry) { |
| 593 | if (req->r_dentry->d_inode) { | 600 | struct inode *dir = req->r_dentry->d_parent->d_inode; |
| 601 | |||
| 602 | if (dir->i_sb != mdsc->client->sb) { | ||
| 603 | /* not this fs! */ | ||
| 604 | inode = req->r_dentry->d_inode; | ||
| 605 | } else if (ceph_snap(dir) != CEPH_NOSNAP) { | ||
| 606 | /* direct snapped/virtual snapdir requests | ||
| 607 | * based on parent dir inode */ | ||
| 608 | struct dentry *dn = | ||
| 609 | get_nonsnap_parent(req->r_dentry->d_parent); | ||
| 610 | inode = dn->d_inode; | ||
| 611 | dout("__choose_mds using nonsnap parent %p\n", inode); | ||
| 612 | } else if (req->r_dentry->d_inode) { | ||
| 613 | /* dentry target */ | ||
| 594 | inode = req->r_dentry->d_inode; | 614 | inode = req->r_dentry->d_inode; |
| 595 | } else { | 615 | } else { |
| 596 | inode = req->r_dentry->d_parent->d_inode; | 616 | /* dir + name */ |
| 617 | inode = dir; | ||
| 597 | hash = req->r_dentry->d_name.hash; | 618 | hash = req->r_dentry->d_name.hash; |
| 598 | is_hash = true; | 619 | is_hash = true; |
| 599 | } | 620 | } |
| 600 | } | 621 | } |
| 622 | |||
| 601 | dout("__choose_mds %p is_hash=%d (%d) mode %d\n", inode, (int)is_hash, | 623 | dout("__choose_mds %p is_hash=%d (%d) mode %d\n", inode, (int)is_hash, |
| 602 | (int)hash, mode); | 624 | (int)hash, mode); |
| 603 | if (!inode) | 625 | if (!inode) |
| @@ -2208,7 +2230,7 @@ static void handle_session(struct ceph_mds_session *session, | |||
| 2208 | pr_info("mds%d reconnect denied\n", session->s_mds); | 2230 | pr_info("mds%d reconnect denied\n", session->s_mds); |
| 2209 | remove_session_caps(session); | 2231 | remove_session_caps(session); |
| 2210 | wake = 1; /* for good measure */ | 2232 | wake = 1; /* for good measure */ |
| 2211 | complete_all(&mdsc->session_close_waiters); | 2233 | wake_up_all(&mdsc->session_close_wq); |
| 2212 | kick_requests(mdsc, mds); | 2234 | kick_requests(mdsc, mds); |
| 2213 | break; | 2235 | break; |
| 2214 | 2236 | ||
| @@ -2302,7 +2324,7 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap, | |||
| 2302 | path = ceph_mdsc_build_path(dentry, &pathlen, &pathbase, 0); | 2324 | path = ceph_mdsc_build_path(dentry, &pathlen, &pathbase, 0); |
| 2303 | if (IS_ERR(path)) { | 2325 | if (IS_ERR(path)) { |
| 2304 | err = PTR_ERR(path); | 2326 | err = PTR_ERR(path); |
| 2305 | BUG_ON(err); | 2327 | goto out_dput; |
| 2306 | } | 2328 | } |
| 2307 | } else { | 2329 | } else { |
| 2308 | path = NULL; | 2330 | path = NULL; |
| @@ -2310,7 +2332,7 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap, | |||
| 2310 | } | 2332 | } |
| 2311 | err = ceph_pagelist_encode_string(pagelist, path, pathlen); | 2333 | err = ceph_pagelist_encode_string(pagelist, path, pathlen); |
| 2312 | if (err) | 2334 | if (err) |
| 2313 | goto out; | 2335 | goto out_free; |
| 2314 | 2336 | ||
| 2315 | spin_lock(&inode->i_lock); | 2337 | spin_lock(&inode->i_lock); |
| 2316 | cap->seq = 0; /* reset cap seq */ | 2338 | cap->seq = 0; /* reset cap seq */ |
| @@ -2354,8 +2376,9 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap, | |||
| 2354 | unlock_kernel(); | 2376 | unlock_kernel(); |
| 2355 | } | 2377 | } |
| 2356 | 2378 | ||
| 2357 | out: | 2379 | out_free: |
| 2358 | kfree(path); | 2380 | kfree(path); |
| 2381 | out_dput: | ||
| 2359 | dput(dentry); | 2382 | dput(dentry); |
| 2360 | return err; | 2383 | return err; |
| 2361 | } | 2384 | } |
| @@ -2876,7 +2899,7 @@ int ceph_mdsc_init(struct ceph_mds_client *mdsc, struct ceph_client *client) | |||
| 2876 | return -ENOMEM; | 2899 | return -ENOMEM; |
| 2877 | 2900 | ||
| 2878 | init_completion(&mdsc->safe_umount_waiters); | 2901 | init_completion(&mdsc->safe_umount_waiters); |
| 2879 | init_completion(&mdsc->session_close_waiters); | 2902 | init_waitqueue_head(&mdsc->session_close_wq); |
| 2880 | INIT_LIST_HEAD(&mdsc->waiting_for_map); | 2903 | INIT_LIST_HEAD(&mdsc->waiting_for_map); |
| 2881 | mdsc->sessions = NULL; | 2904 | mdsc->sessions = NULL; |
| 2882 | mdsc->max_sessions = 0; | 2905 | mdsc->max_sessions = 0; |
| @@ -3021,6 +3044,23 @@ void ceph_mdsc_sync(struct ceph_mds_client *mdsc) | |||
| 3021 | wait_event(mdsc->cap_flushing_wq, check_cap_flush(mdsc, want_flush)); | 3044 | wait_event(mdsc->cap_flushing_wq, check_cap_flush(mdsc, want_flush)); |
| 3022 | } | 3045 | } |
| 3023 | 3046 | ||
| 3047 | /* | ||
| 3048 | * true if all sessions are closed, or we force unmount | ||
| 3049 | */ | ||
| 3050 | bool done_closing_sessions(struct ceph_mds_client *mdsc) | ||
| 3051 | { | ||
| 3052 | int i, n = 0; | ||
| 3053 | |||
| 3054 | if (mdsc->client->mount_state == CEPH_MOUNT_SHUTDOWN) | ||
| 3055 | return true; | ||
| 3056 | |||
| 3057 | mutex_lock(&mdsc->mutex); | ||
| 3058 | for (i = 0; i < mdsc->max_sessions; i++) | ||
| 3059 | if (mdsc->sessions[i]) | ||
| 3060 | n++; | ||
| 3061 | mutex_unlock(&mdsc->mutex); | ||
| 3062 | return n == 0; | ||
| 3063 | } | ||
| 3024 | 3064 | ||
| 3025 | /* | 3065 | /* |
| 3026 | * called after sb is ro. | 3066 | * called after sb is ro. |
| @@ -3029,45 +3069,32 @@ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc) | |||
| 3029 | { | 3069 | { |
| 3030 | struct ceph_mds_session *session; | 3070 | struct ceph_mds_session *session; |
| 3031 | int i; | 3071 | int i; |
| 3032 | int n; | ||
| 3033 | struct ceph_client *client = mdsc->client; | 3072 | struct ceph_client *client = mdsc->client; |
| 3034 | unsigned long started, timeout = client->mount_args->mount_timeout * HZ; | 3073 | unsigned long timeout = client->mount_args->mount_timeout * HZ; |
| 3035 | 3074 | ||
| 3036 | dout("close_sessions\n"); | 3075 | dout("close_sessions\n"); |
| 3037 | 3076 | ||
| 3038 | mutex_lock(&mdsc->mutex); | ||
| 3039 | |||
| 3040 | /* close sessions */ | 3077 | /* close sessions */ |
| 3041 | started = jiffies; | 3078 | mutex_lock(&mdsc->mutex); |
| 3042 | while (time_before(jiffies, started + timeout)) { | 3079 | for (i = 0; i < mdsc->max_sessions; i++) { |
| 3043 | dout("closing sessions\n"); | 3080 | session = __ceph_lookup_mds_session(mdsc, i); |
| 3044 | n = 0; | 3081 | if (!session) |
| 3045 | for (i = 0; i < mdsc->max_sessions; i++) { | 3082 | continue; |
| 3046 | session = __ceph_lookup_mds_session(mdsc, i); | ||
| 3047 | if (!session) | ||
| 3048 | continue; | ||
| 3049 | mutex_unlock(&mdsc->mutex); | ||
| 3050 | mutex_lock(&session->s_mutex); | ||
| 3051 | __close_session(mdsc, session); | ||
| 3052 | mutex_unlock(&session->s_mutex); | ||
| 3053 | ceph_put_mds_session(session); | ||
| 3054 | mutex_lock(&mdsc->mutex); | ||
| 3055 | n++; | ||
| 3056 | } | ||
| 3057 | if (n == 0) | ||
| 3058 | break; | ||
| 3059 | |||
| 3060 | if (client->mount_state == CEPH_MOUNT_SHUTDOWN) | ||
| 3061 | break; | ||
| 3062 | |||
| 3063 | dout("waiting for sessions to close\n"); | ||
| 3064 | mutex_unlock(&mdsc->mutex); | 3083 | mutex_unlock(&mdsc->mutex); |
| 3065 | wait_for_completion_timeout(&mdsc->session_close_waiters, | 3084 | mutex_lock(&session->s_mutex); |
| 3066 | timeout); | 3085 | __close_session(mdsc, session); |
| 3086 | mutex_unlock(&session->s_mutex); | ||
| 3087 | ceph_put_mds_session(session); | ||
| 3067 | mutex_lock(&mdsc->mutex); | 3088 | mutex_lock(&mdsc->mutex); |
| 3068 | } | 3089 | } |
| 3090 | mutex_unlock(&mdsc->mutex); | ||
| 3091 | |||
| 3092 | dout("waiting for sessions to close\n"); | ||
| 3093 | wait_event_timeout(mdsc->session_close_wq, done_closing_sessions(mdsc), | ||
| 3094 | timeout); | ||
| 3069 | 3095 | ||
| 3070 | /* tear down remaining sessions */ | 3096 | /* tear down remaining sessions */ |
| 3097 | mutex_lock(&mdsc->mutex); | ||
| 3071 | for (i = 0; i < mdsc->max_sessions; i++) { | 3098 | for (i = 0; i < mdsc->max_sessions; i++) { |
| 3072 | if (mdsc->sessions[i]) { | 3099 | if (mdsc->sessions[i]) { |
| 3073 | session = get_session(mdsc->sessions[i]); | 3100 | session = get_session(mdsc->sessions[i]); |
| @@ -3080,9 +3107,7 @@ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc) | |||
| 3080 | mutex_lock(&mdsc->mutex); | 3107 | mutex_lock(&mdsc->mutex); |
| 3081 | } | 3108 | } |
| 3082 | } | 3109 | } |
| 3083 | |||
| 3084 | WARN_ON(!list_empty(&mdsc->cap_delay_list)); | 3110 | WARN_ON(!list_empty(&mdsc->cap_delay_list)); |
| 3085 | |||
| 3086 | mutex_unlock(&mdsc->mutex); | 3111 | mutex_unlock(&mdsc->mutex); |
| 3087 | 3112 | ||
| 3088 | ceph_cleanup_empty_realms(mdsc); | 3113 | ceph_cleanup_empty_realms(mdsc); |
