Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ceph: EIO all operations after forced umount

This patch makes try_get_cap_refs() and __do_request() check
if the file system was forced umount, and return -EIO if it was.
This patch also adds a helper function to drops dirty caps and
wakes up blocking operation.

Signed-off-by: Yan, Zheng <zyan@redhat.com>

authored by

Yan, Zheng and committed by
Ilya Dryomov
48fec5d0 64291f7d

+54 -12
+1 -1
fs/ceph/addr.c
··· 717 717 wbc->sync_mode == WB_SYNC_NONE ? "NONE" : 718 718 (wbc->sync_mode == WB_SYNC_ALL ? "ALL" : "HOLD")); 719 719 720 - if (fsc->mount_state == CEPH_MOUNT_SHUTDOWN) { 720 + if (ACCESS_ONCE(fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) { 721 721 pr_warn("writepage_start %p on forced umount\n", inode); 722 722 return -EIO; /* we're in a forced umount, don't write! */ 723 723 }
+8
fs/ceph/caps.c
··· 2413 2413 goto out_unlock; 2414 2414 } 2415 2415 2416 + if (!__ceph_is_any_caps(ci) && 2417 + ACCESS_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) { 2418 + dout("get_cap_refs %p forced umount\n", inode); 2419 + *err = -EIO; 2420 + ret = 1; 2421 + goto out_unlock; 2422 + } 2423 + 2416 2424 dout("get_cap_refs %p have %s needed %s\n", inode, 2417 2425 ceph_cap_string(have), ceph_cap_string(need)); 2418 2426 }
+43 -11
fs/ceph/mds_client.c
··· 2107 2107 msg = create_request_message(mdsc, req, mds, drop_cap_releases); 2108 2108 if (IS_ERR(msg)) { 2109 2109 req->r_err = PTR_ERR(msg); 2110 - complete_request(mdsc, req); 2111 2110 return PTR_ERR(msg); 2112 2111 } 2113 2112 req->r_request = msg; ··· 2134 2135 { 2135 2136 struct ceph_mds_session *session = NULL; 2136 2137 int mds = -1; 2137 - int err = -EAGAIN; 2138 + int err = 0; 2138 2139 2139 2140 if (req->r_err || req->r_got_result) { 2140 2141 if (req->r_aborted) ··· 2145 2146 if (req->r_timeout && 2146 2147 time_after_eq(jiffies, req->r_started + req->r_timeout)) { 2147 2148 dout("do_request timed out\n"); 2149 + err = -EIO; 2150 + goto finish; 2151 + } 2152 + if (ACCESS_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) { 2153 + dout("do_request forced umount\n"); 2148 2154 err = -EIO; 2149 2155 goto finish; 2150 2156 } ··· 2200 2196 2201 2197 out_session: 2202 2198 ceph_put_mds_session(session); 2199 + finish: 2200 + if (err) { 2201 + dout("__do_request early error %d\n", err); 2202 + req->r_err = err; 2203 + complete_request(mdsc, req); 2204 + __unregister_request(mdsc, req); 2205 + } 2203 2206 out: 2204 2207 return err; 2205 - 2206 - finish: 2207 - req->r_err = err; 2208 - complete_request(mdsc, req); 2209 - goto out; 2210 2208 } 2211 2209 2212 2210 /* ··· 2295 2289 2296 2290 if (req->r_err) { 2297 2291 err = req->r_err; 2298 - __unregister_request(mdsc, req); 2299 - dout("do_request early error %d\n", err); 2300 2292 goto out; 2301 2293 } 2302 2294 ··· 3559 3555 { 3560 3556 u64 want_tid, want_flush, want_snap; 3561 3557 3562 - if (mdsc->fsc->mount_state == CEPH_MOUNT_SHUTDOWN) 3558 + if (ACCESS_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) 3563 3559 return; 3564 3560 3565 3561 dout("sync\n"); ··· 3588 3584 */ 3589 3585 static bool done_closing_sessions(struct ceph_mds_client *mdsc) 3590 3586 { 3591 - if (mdsc->fsc->mount_state == CEPH_MOUNT_SHUTDOWN) 3587 + if (ACCESS_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) 3592 3588 return true; 3593 3589 return atomic_read(&mdsc->num_sessions) == 0; 3594 3590 } ··· 3645 3641 cancel_delayed_work_sync(&mdsc->delayed_work); /* cancel timer */ 3646 3642 3647 3643 dout("stopped\n"); 3644 + } 3645 + 3646 + void ceph_mdsc_force_umount(struct ceph_mds_client *mdsc) 3647 + { 3648 + struct ceph_mds_session *session; 3649 + int mds; 3650 + 3651 + dout("force umount\n"); 3652 + 3653 + mutex_lock(&mdsc->mutex); 3654 + for (mds = 0; mds < mdsc->max_sessions; mds++) { 3655 + session = __ceph_lookup_mds_session(mdsc, mds); 3656 + if (!session) 3657 + continue; 3658 + mutex_unlock(&mdsc->mutex); 3659 + mutex_lock(&session->s_mutex); 3660 + __close_session(mdsc, session); 3661 + if (session->s_state == CEPH_MDS_SESSION_CLOSING) { 3662 + cleanup_session_requests(mdsc, session); 3663 + remove_session_caps(session); 3664 + } 3665 + mutex_unlock(&session->s_mutex); 3666 + ceph_put_mds_session(session); 3667 + mutex_lock(&mdsc->mutex); 3668 + kick_requests(mdsc, mds); 3669 + } 3670 + __wake_requests(mdsc, &mdsc->waiting_for_map); 3671 + mutex_unlock(&mdsc->mutex); 3648 3672 } 3649 3673 3650 3674 static void ceph_mdsc_stop(struct ceph_mds_client *mdsc)
+1
fs/ceph/mds_client.h
··· 366 366 367 367 extern int ceph_mdsc_init(struct ceph_fs_client *fsc); 368 368 extern void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc); 369 + extern void ceph_mdsc_force_umount(struct ceph_mds_client *mdsc); 369 370 extern void ceph_mdsc_destroy(struct ceph_fs_client *fsc); 370 371 371 372 extern void ceph_mdsc_sync(struct ceph_mds_client *mdsc);
+1
fs/ceph/super.c
··· 708 708 if (!fsc) 709 709 return; 710 710 fsc->mount_state = CEPH_MOUNT_SHUTDOWN; 711 + ceph_mdsc_force_umount(fsc->mdsc); 711 712 return; 712 713 } 713 714