lkml.org 
[lkml]   [2022]   [Jan]   [31]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.16 179/200] ceph: put the requests/sessions when it fails to alloc memory
    Date
    From: Xiubo Li <xiubli@redhat.com>

    [ Upstream commit 89d43d0551a848e70e63d9ba11534aaeabc82443 ]

    When failing to allocate the sessions memory we should make sure
    the req1 and req2 and the sessions get put. And also in case the
    max_sessions decreased so when kreallocate the new memory some
    sessions maybe missed being put.

    And if the max_sessions is 0 krealloc will return ZERO_SIZE_PTR,
    which will lead to a distinct access fault.

    URL: https://tracker.ceph.com/issues/53819
    Fixes: e1a4541ec0b9 ("ceph: flush the mdlog before waiting on unsafe reqs")
    Signed-off-by: Xiubo Li <xiubli@redhat.com>
    Reviewed-by: Venky Shankar <vshankar@redhat.com>
    Reviewed-by: Jeff Layton <jlayton@kernel.org>
    Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    fs/ceph/caps.c | 55 +++++++++++++++++++++++++++++++++-----------------
    1 file changed, 37 insertions(+), 18 deletions(-)

    diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
    index c447fa2e2d1fe..2f8696f3b925d 100644
    --- a/fs/ceph/caps.c
    +++ b/fs/ceph/caps.c
    @@ -2218,6 +2218,7 @@ static int unsafe_request_wait(struct inode *inode)
    struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
    struct ceph_inode_info *ci = ceph_inode(inode);
    struct ceph_mds_request *req1 = NULL, *req2 = NULL;
    + unsigned int max_sessions;
    int ret, err = 0;

    spin_lock(&ci->i_unsafe_lock);
    @@ -2235,37 +2236,45 @@ static int unsafe_request_wait(struct inode *inode)
    }
    spin_unlock(&ci->i_unsafe_lock);

    + /*
    + * The mdsc->max_sessions is unlikely to be changed
    + * mostly, here we will retry it by reallocating the
    + * sessions array memory to get rid of the mdsc->mutex
    + * lock.
    + */
    +retry:
    + max_sessions = mdsc->max_sessions;
    +
    /*
    * Trigger to flush the journal logs in all the relevant MDSes
    * manually, or in the worst case we must wait at most 5 seconds
    * to wait the journal logs to be flushed by the MDSes periodically.
    */
    - if (req1 || req2) {
    + if ((req1 || req2) && likely(max_sessions)) {
    struct ceph_mds_session **sessions = NULL;
    struct ceph_mds_session *s;
    struct ceph_mds_request *req;
    - unsigned int max;
    int i;

    - /*
    - * The mdsc->max_sessions is unlikely to be changed
    - * mostly, here we will retry it by reallocating the
    - * sessions arrary memory to get rid of the mdsc->mutex
    - * lock.
    - */
    -retry:
    - max = mdsc->max_sessions;
    - sessions = krealloc(sessions, max * sizeof(s), __GFP_ZERO);
    - if (!sessions)
    - return -ENOMEM;
    + sessions = kzalloc(max_sessions * sizeof(s), GFP_KERNEL);
    + if (!sessions) {
    + err = -ENOMEM;
    + goto out;
    + }

    spin_lock(&ci->i_unsafe_lock);
    if (req1) {
    list_for_each_entry(req, &ci->i_unsafe_dirops,
    r_unsafe_dir_item) {
    s = req->r_session;
    - if (unlikely(s->s_mds >= max)) {
    + if (unlikely(s->s_mds >= max_sessions)) {
    spin_unlock(&ci->i_unsafe_lock);
    + for (i = 0; i < max_sessions; i++) {
    + s = sessions[i];
    + if (s)
    + ceph_put_mds_session(s);
    + }
    + kfree(sessions);
    goto retry;
    }
    if (!sessions[s->s_mds]) {
    @@ -2278,8 +2287,14 @@ retry:
    list_for_each_entry(req, &ci->i_unsafe_iops,
    r_unsafe_target_item) {
    s = req->r_session;
    - if (unlikely(s->s_mds >= max)) {
    + if (unlikely(s->s_mds >= max_sessions)) {
    spin_unlock(&ci->i_unsafe_lock);
    + for (i = 0; i < max_sessions; i++) {
    + s = sessions[i];
    + if (s)
    + ceph_put_mds_session(s);
    + }
    + kfree(sessions);
    goto retry;
    }
    if (!sessions[s->s_mds]) {
    @@ -2300,7 +2315,7 @@ retry:
    spin_unlock(&ci->i_ceph_lock);

    /* send flush mdlog request to MDSes */
    - for (i = 0; i < max; i++) {
    + for (i = 0; i < max_sessions; i++) {
    s = sessions[i];
    if (s) {
    send_flush_mdlog(s);
    @@ -2317,15 +2332,19 @@ retry:
    ceph_timeout_jiffies(req1->r_timeout));
    if (ret)
    err = -EIO;
    - ceph_mdsc_put_request(req1);
    }
    if (req2) {
    ret = !wait_for_completion_timeout(&req2->r_safe_completion,
    ceph_timeout_jiffies(req2->r_timeout));
    if (ret)
    err = -EIO;
    - ceph_mdsc_put_request(req2);
    }
    +
    +out:
    + if (req1)
    + ceph_mdsc_put_request(req1);
    + if (req2)
    + ceph_mdsc_put_request(req2);
    return err;
    }

    --
    2.34.1


    \
     
     \ /
      Last update: 2022-01-31 12:41    [W:4.054 / U:0.580 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site