lkml.org 
[lkml]   [2015]   [Jan]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.14 04/77] ocfs2: fix the wrong directory passed to ocfs2_lookup_ino_from_name() when link file
    Date
    3.14-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Xue jiufei <xuejiufei@huawei.com>

    commit 53dc20b9a3d928b0744dad5aee65b610de1cc85d upstream.

    In ocfs2_link(), the parent directory inode passed to function
    ocfs2_lookup_ino_from_name() is wrong. Parameter dir is the parent of
    new_dentry not old_dentry. We should get old_dir from old_dentry and
    lookup old_dentry in old_dir in case another node remove the old dentry.

    With this change, hard linking works again, when paths are relative with
    at least one subdirectory. This is how the problem was reproducable:

    # mkdir a
    # mkdir b
    # touch a/test
    # ln a/test b/test
    ln: failed to create hard link `b/test' => `a/test': No such file or directory

    However when creating links in the same dir, it worked well.

    Now the link gets created.

    Fixes: 0e048316ff57 ("ocfs2: check existence of old dentry in ocfs2_link()")
    Signed-off-by: joyce.xue <xuejiufei@huawei.com>
    Reported-by: Szabo Aron - UBIT <aron@ubit.hu>
    Cc: Mark Fasheh <mfasheh@suse.com>
    Cc: Joel Becker <jlbec@evilplan.org>
    Tested-by: Aron Szabo <aron@ubit.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    fs/ocfs2/namei.c | 43 +++++++++++++++++++++++++++++++++++--------
    1 file changed, 35 insertions(+), 8 deletions(-)

    --- a/fs/ocfs2/namei.c
    +++ b/fs/ocfs2/namei.c
    @@ -94,6 +94,14 @@ static int ocfs2_create_symlink_data(str
    struct inode *inode,
    const char *symname);

    +static int ocfs2_double_lock(struct ocfs2_super *osb,
    + struct buffer_head **bh1,
    + struct inode *inode1,
    + struct buffer_head **bh2,
    + struct inode *inode2,
    + int rename);
    +
    +static void ocfs2_double_unlock(struct inode *inode1, struct inode *inode2);
    /* An orphan dir name is an 8 byte value, printed as a hex string */
    #define OCFS2_ORPHAN_NAMELEN ((int)(2 * sizeof(u64)))

    @@ -656,8 +664,10 @@ static int ocfs2_link(struct dentry *old
    {
    handle_t *handle;
    struct inode *inode = old_dentry->d_inode;
    + struct inode *old_dir = old_dentry->d_parent->d_inode;
    int err;
    struct buffer_head *fe_bh = NULL;
    + struct buffer_head *old_dir_bh = NULL;
    struct buffer_head *parent_fe_bh = NULL;
    struct ocfs2_dinode *fe = NULL;
    struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
    @@ -674,19 +684,33 @@ static int ocfs2_link(struct dentry *old

    dquot_initialize(dir);

    - err = ocfs2_inode_lock_nested(dir, &parent_fe_bh, 1, OI_LS_PARENT);
    + err = ocfs2_double_lock(osb, &old_dir_bh, old_dir,
    + &parent_fe_bh, dir, 0);
    if (err < 0) {
    if (err != -ENOENT)
    mlog_errno(err);
    return err;
    }

    + /* make sure both dirs have bhs
    + * get an extra ref on old_dir_bh if old==new */
    + if (!parent_fe_bh) {
    + if (old_dir_bh) {
    + parent_fe_bh = old_dir_bh;
    + get_bh(parent_fe_bh);
    + } else {
    + mlog(ML_ERROR, "%s: no old_dir_bh!\n", osb->uuid_str);
    + err = -EIO;
    + goto out;
    + }
    + }
    +
    if (!dir->i_nlink) {
    err = -ENOENT;
    goto out;
    }

    - err = ocfs2_lookup_ino_from_name(dir, old_dentry->d_name.name,
    + err = ocfs2_lookup_ino_from_name(old_dir, old_dentry->d_name.name,
    old_dentry->d_name.len, &old_de_ino);
    if (err) {
    err = -ENOENT;
    @@ -779,10 +803,11 @@ out_unlock_inode:
    ocfs2_inode_unlock(inode, 1);

    out:
    - ocfs2_inode_unlock(dir, 1);
    + ocfs2_double_unlock(old_dir, dir);

    brelse(fe_bh);
    brelse(parent_fe_bh);
    + brelse(old_dir_bh);

    ocfs2_free_dir_lookup_result(&lookup);

    @@ -991,14 +1016,15 @@ leave:
    }

    /*
    - * The only place this should be used is rename!
    + * The only place this should be used is rename and link!
    * if they have the same id, then the 1st one is the only one locked.
    */
    static int ocfs2_double_lock(struct ocfs2_super *osb,
    struct buffer_head **bh1,
    struct inode *inode1,
    struct buffer_head **bh2,
    - struct inode *inode2)
    + struct inode *inode2,
    + int rename)
    {
    int status;
    struct ocfs2_inode_info *oi1 = OCFS2_I(inode1);
    @@ -1028,7 +1054,7 @@ static int ocfs2_double_lock(struct ocfs
    }
    /* lock id2 */
    status = ocfs2_inode_lock_nested(inode2, bh2, 1,
    - OI_LS_RENAME1);
    + rename == 1 ? OI_LS_RENAME1 : OI_LS_PARENT);
    if (status < 0) {
    if (status != -ENOENT)
    mlog_errno(status);
    @@ -1037,7 +1063,8 @@ static int ocfs2_double_lock(struct ocfs
    }

    /* lock id1 */
    - status = ocfs2_inode_lock_nested(inode1, bh1, 1, OI_LS_RENAME2);
    + status = ocfs2_inode_lock_nested(inode1, bh1, 1,
    + rename == 1 ? OI_LS_RENAME2 : OI_LS_PARENT);
    if (status < 0) {
    /*
    * An error return must mean that no cluster locks
    @@ -1137,7 +1164,7 @@ static int ocfs2_rename(struct inode *ol

    /* if old and new are the same, this'll just do one lock. */
    status = ocfs2_double_lock(osb, &old_dir_bh, old_dir,
    - &new_dir_bh, new_dir);
    + &new_dir_bh, new_dir, 1);
    if (status < 0) {
    mlog_errno(status);
    goto bail;



    \
     
     \ /
      Last update: 2015-01-14 09:41    [W:4.128 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site