From aa6c5b9d40a5e75fd9855bee84b861afc01ae1e8 Mon Sep 17 00:00:00 2001 From: Andreas Dilger Date: Tue, 22 Jan 2013 17:19:21 -0700 Subject: [PATCH] LU-2638 osd-ldiskfs: clean up insertion of ".." FID Prototype patch, not for landing, since it is missing some code. Clean up the handling of ".." insertion, so that we don't try to insert a FID-in-dirent if the ".." directory entry does not have space for it. This is only relevant in case of upgraded 1.8 filesystems for directories created before the "dirdata" feature was enabled, or in case of 2.x filesystems that have underwent backup and restore. For new directories there should always be enough space, assuming the "dirdata" feature is available. For existing directories that undergo a rename, check the dentry d_fsdata field to determine if the looked-up entry had a FID stored previously and should be updated, or if it is an old directory that should not get a FID. Signed-off-by: Andreas Dilger Change-Id: Iaa5c9dee48eb1db2d98bf537d497c3df2c96dc2a --- .../patches/ext4-kill-dx_root-rhel6.patch | 37 ++-- lustre/osd-ldiskfs/osd_handler.c | 232 +++++++++++---------- 2 files changed, 141 insertions(+), 128 deletions(-) diff --git a/ldiskfs/kernel_patches/patches/ext4-kill-dx_root-rhel6.patch b/ldiskfs/kernel_patches/patches/ext4-kill-dx_root-rhel6.patch index 6631dde..06ed1fa 100644 --- a/ldiskfs/kernel_patches/patches/ext4-kill-dx_root-rhel6.patch +++ b/ldiskfs/kernel_patches/patches/ext4-kill-dx_root-rhel6.patch @@ -39,15 +39,15 @@ Index: linux-2.6.32.i386/fs/ext4/namei.c * Future: use high four bits of block for coalesce-on-delete flags * Mask them off for now. */ -+struct dx_root_info * dx_get_dx_info(struct ext4_dir_entry_2 *de) ++struct dx_root_info *dx_get_dx_info(struct ext4_dir_entry_2 *de) +{ -+ /* get dotdot first */ -+ de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(1)); ++ /* get dotdot first */ ++ de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(1)); + -+ /* dx root info is after dotdot entry */ -+ de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(2)); ++ /* dx root info is after dotdot entry */ ++ de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(2)); + -+ return (struct dx_root_info *) de; ++ return (struct dx_root_info *) de; +} static inline ext4_lblk_t dx_get_block(struct dx_entry *entry) @@ -57,7 +57,7 @@ Index: linux-2.6.32.i386/fs/ext4/namei.c unsigned count, indirect; struct dx_entry *at, *entries, *p, *q, *m; - struct dx_root *root; -+ struct dx_root_info * info; ++ struct dx_root_info *info; struct buffer_head *bh; struct dx_frame *frame = frame_in; u32 hash; @@ -70,13 +70,13 @@ Index: linux-2.6.32.i386/fs/ext4/namei.c - root->info.hash_version != DX_HASH_HALF_MD4 && - root->info.hash_version != DX_HASH_LEGACY) { + -+ info = dx_get_dx_info((struct ext4_dir_entry_2*)bh->b_data); ++ info = dx_get_dx_info((struct ext4_dir_entry_2 *)bh->b_data); + if (info->hash_version != DX_HASH_TEA && + info->hash_version != DX_HASH_HALF_MD4 && + info->hash_version != DX_HASH_LEGACY) { ext4_warning(dir->i_sb, "Unrecognised inode hash code %d for directory " - "#%lu", root->info.hash_version, dir->i_ino); -+ "#%lu", info->hash_version, dir->i_ino); ++ "#%lu", info->hash_version, dir->i_ino); brelse(bh); *err = ERR_BAD_DX_DIR; goto fail; @@ -86,7 +86,7 @@ Index: linux-2.6.32.i386/fs/ext4/namei.c if (hinfo->hash_version <= DX_HASH_TEA) hinfo->hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed; -@@ -425,27 +427,26 @@ +@@ -425,27 +427,27 @@ ext4fs_dirhash(d_name->name, d_name->len, hinfo); hash = hinfo->hash; @@ -101,7 +101,8 @@ Index: linux-2.6.32.i386/fs/ext4/namei.c } - if ((indirect = root->info.indirect_levels) > 1) { -+ if ((indirect = info->indirect_levels) > 1) { ++ indirect = info->indirect_levels; ++ if (indirect > 1) { ext4_warning(dir->i_sb, "Unimplemented inode hash depth: %#06x", - root->info.indirect_levels); + info->indirect_levels); @@ -129,7 +130,7 @@ Index: linux-2.6.32.i386/fs/ext4/namei.c return; - if (((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels) -+ info = dx_get_dx_info((struct ext4_dir_entry_2*)frames[0].bh->b_data); ++ info = dx_get_dx_info((struct ext4_dir_entry_2 *)frames[0].bh->b_data); + if (info->indirect_levels) brelse(frames[1].bh); brelse(frames[0].bh); @@ -170,7 +171,7 @@ Index: linux-2.6.32.i386/fs/ext4/namei.c - if ((char *) de >= (((char *) root) + blocksize)) { + de = (struct ext4_dir_entry_2 *)((char *)dotdot_de + + ext4_rec_len_from_disk(dotdot_de->rec_len, blocksize)); -+ if ((char *) de >= (((char *) dot_de) + blocksize)) { ++ if ((char *)de >= (((char *)dot_de) + blocksize)) { ext4_error(dir->i_sb, "invalid rec_len for '..' in inode %lu", dir->i_ino); @@ -178,7 +179,7 @@ Index: linux-2.6.32.i386/fs/ext4/namei.c return -EIO; } - len = ((char *) root) + blocksize - (char *) de; -+ len = ((char *) dot_de) + blocksize - (char *) de; ++ len = ((char *)dot_de) + blocksize - (char *)de; /* Allocate new block for the 0th block's dirents */ bh2 = ext4_append(handle, dir, &block, &retval); @@ -198,7 +199,7 @@ Index: linux-2.6.32.i386/fs/ext4/namei.c + + /* initialize hashing info */ + dx_info = dx_get_dx_info(dot_de); -+ memset (dx_info, 0, sizeof(*dx_info)); ++ memset(dx_info, 0, sizeof(*dx_info)); + dx_info->info_length = sizeof(*dx_info); + dx_info->hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version; + @@ -219,7 +220,7 @@ Index: linux-2.6.32.i386/fs/ext4/namei.c goto journal_error; brelse (bh2); } else { -+ struct dx_root_info * info; ++ struct dx_root_info *info; dxtrace(printk(KERN_DEBUG "Creating second level index...\n")); memcpy((char *) entries2, (char *) entries, @@ -228,8 +229,8 @@ Index: linux-2.6.32.i386/fs/ext4/namei.c dx_set_count(entries, 1); dx_set_block(entries + 0, newblock); - ((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels = 1; -+ info = dx_get_dx_info((struct ext4_dir_entry_2*) -+ frames[0].bh->b_data); ++ info = dx_get_dx_info((struct ext4_dir_entry_2 *) ++ frames[0].bh->b_data); + info->indirect_levels = 1; /* Add new access path frame */ diff --git a/lustre/osd-ldiskfs/osd_handler.c b/lustre/osd-ldiskfs/osd_handler.c index c07b928..a9b86eb 100644 --- a/lustre/osd-ldiskfs/osd_handler.c +++ b/lustre/osd-ldiskfs/osd_handler.c @@ -3170,112 +3170,125 @@ static int osd_index_iam_insert(const struct lu_env *env, struct dt_object *dt, } /** - * Calls ldiskfs_add_entry() to add directory entry - * into the directory. This is required for - * interoperability mode (b11826) + * Calls ldiskfs_add_entry() to add directory entry into the directory. + * + * \param info thread stack info + * \param pobj parent OSD object + * \param cinode child VFS inode + * \param name child name to be inserted in directory entry + * \param fid child FID to be inserted into directory entry + * \param hlock tree lock for pdirops + * \param th OSD transaction handle * * \retval 0, on success * \retval -ve, on error */ -static int __osd_ea_add_rec(struct osd_thread_info *info, - struct osd_object *pobj, struct inode *cinode, - const char *name, const struct dt_rec *fid, - struct htree_lock *hlock, struct thandle *th) -{ - struct ldiskfs_dentry_param *ldp; - struct dentry *child; - struct osd_thandle *oth; - int rc; - - oth = container_of(th, struct osd_thandle, ot_super); - LASSERT(oth->ot_handle != NULL); - LASSERT(oth->ot_handle->h_transaction != NULL); - - child = osd_child_dentry_get(info->oti_env, pobj, name, strlen(name)); - - /* XXX: remove fid_is_igif() check here. - * IGIF check is just to handle insertion of .. when it is 'ROOT', - * it is IGIF now but needs FID in dir entry as well for readdir - * to work. - * LU-838 should fix that and remove fid_is_igif() check */ - if (fid_is_igif((struct lu_fid *)fid) || - fid_is_norm((struct lu_fid *)fid)) { - ldp = (struct ldiskfs_dentry_param *)info->oti_ldp; - osd_get_ldiskfs_dirent_param(ldp, fid); - child->d_fsdata = (void *)ldp; - } else { - child->d_fsdata = NULL; - } +static int osd_ea_add_norm(struct osd_thread_info *info, + struct osd_object *pobj, struct inode *cinode, + const char *name, const struct dt_rec *fid, + struct htree_lock *hlock, struct thandle *th) +{ + struct ldiskfs_dentry_param *ldp; + struct dentry *dchild; + struct osd_thandle *oth; + int rc; + + oth = container_of(th, struct osd_thandle, ot_super); + LASSERT(oth->ot_handle != NULL); + LASSERT(oth->ot_handle->h_transaction != NULL); + + dchild = osd_child_dentry_get(info->oti_env, pobj, name, strlen(name)); + + if (fid_is_igif((struct lu_fid *)fid) || + fid_is_norm((struct lu_fid *)fid)) { + ldp = (struct ldiskfs_dentry_param *)info->oti_ldp; + osd_get_ldiskfs_dirent_param(ldp, fid); + dchild->d_fsdata = (void *)ldp; + } else { + dchild->d_fsdata = NULL; + } LASSERT(pobj->oo_inode); ll_vfs_dq_init(pobj->oo_inode); - rc = osd_ldiskfs_add_entry(oth->ot_handle, child, cinode, hlock); + rc = osd_ldiskfs_add_entry(oth->ot_handle, dchild, cinode, hlock); - RETURN(rc); + RETURN(rc); } /** * Calls ldiskfs_add_dot_dotdot() to add dot and dotdot entries * into the directory.Also sets flags into osd object to * indicate dot and dotdot are created. This is required for - * interoperability mode (b11826) + * interoperability mode (b=11826) * - * \param dir directory for dot and dotdot fixup. - * \param obj child object for linking + * \param info OSD thread stack + * \param obj OSD object that is being updated + * \param parent_dir VFS inode of rOSD object that is being updated + * \param name name of entry being added (".", "..", other) + * \param dot_fid FID of the directory itself + * \param dot_dot_fid FID of the parent directory. * * \retval 0, on success * \retval -ve, on error */ static int osd_add_dot_dotdot(struct osd_thread_info *info, - struct osd_object *dir, - struct inode *parent_dir, const char *name, - const struct dt_rec *dot_fid, - const struct dt_rec *dot_dot_fid, - struct thandle *th) -{ - struct inode *inode = dir->oo_inode; - struct ldiskfs_dentry_param *dot_ldp; - struct ldiskfs_dentry_param *dot_dot_ldp; - struct osd_thandle *oth; - int result = 0; + struct osd_object *obj, + struct inode *parent_dir, const char *name, + const struct dt_rec *dot_fid, + const struct dt_rec *dot_dot_fid, + struct thandle *th) +{ + struct inode *inode = obj->oo_inode; + struct osd_thandle *oth; + int rc = 0; - oth = container_of(th, struct osd_thandle, ot_super); - LASSERT(oth->ot_handle->h_transaction != NULL); - LASSERT(S_ISDIR(dir->oo_inode->i_mode)); + oth = container_of(th, struct osd_thandle, ot_super); + LASSERT(oth->ot_handle->h_transaction != NULL); + LASSERT(S_ISDIR(obj->oo_inode->i_mode)); - if (strcmp(name, dot) == 0) { - if (dir->oo_compat_dot_created) { - result = -EEXIST; - } else { - LASSERT(inode == parent_dir); - dir->oo_compat_dot_created = 1; - result = 0; - } - } else if(strcmp(name, dotdot) == 0) { - dot_ldp = (struct ldiskfs_dentry_param *)info->oti_ldp; - dot_dot_ldp = (struct ldiskfs_dentry_param *)info->oti_ldp2; - - if (!dir->oo_compat_dot_created) - return -EINVAL; - if (!fid_is_igif((struct lu_fid *)dot_fid)) { - osd_get_ldiskfs_dirent_param(dot_ldp, dot_fid); - osd_get_ldiskfs_dirent_param(dot_dot_ldp, dot_dot_fid); - } else { - dot_ldp = NULL; - dot_dot_ldp = NULL; - } - /* in case of rename, dotdot is already created */ - if (dir->oo_compat_dotdot_created) { - return __osd_ea_add_rec(info, dir, parent_dir, name, - dot_dot_fid, NULL, th); - } + if (strcmp(name, dot) == 0) { + if (obj->oo_compat_dot_created) { + result = -EEXIST; + } else { + LASSERT(inode == parent_dir); + obj->oo_compat_dot_created = 1; + result = 0; + } + } else if (strcmp(name, dotdot) == 0) { + struct ldiskfs_dentry_param *dot_ldp; + struct ldiskfs_dentry_param *dot_dot_ldp; + + if (!obj->oo_compat_dot_created) + return -EINVAL; + + dot_dot_ldp = (struct ldiskfs_dentry_param *)info->oti_ldp2; + osd_get_ldiskfs_dirent_param(dot_dot_ldp, dot_dot_fid); + + /* In case of rename, dot/dotdot are already created, but + * we only try to store the FID if it was there previously. + * Otherwise, it may clobber the dx_root_info and start of + * the next entry, or be inserted later in the directory. */ + if (obj->oo_compat_dotdot_created) { + dchild = osd_child_dentry_get(info->oti_env, obj, + name, strlen(name)); + rc = osd_get_fid_from_dentry(env, obj, parent_dir, + dchild); + if (dchild->d_fsdata != NULL) + dchild->d_fsdata = ldp; + + ll_vfs_dq_init(obj->oo_inode); + rc = osd_ldiskfs_add_entry(oth->ot_handle, dchild, + cinode, NULL); + } - result = ldiskfs_add_dot_dotdot(oth->ot_handle, parent_dir, - inode, dot_ldp, dot_dot_ldp); - if (result == 0) - dir->oo_compat_dotdot_created = 1; - } + dot_ldp = (struct ldiskfs_dentry_param *)info->oti_ldp; + osd_get_ldiskfs_dirent_param(dot_ldp, dot_fid); - return result; + result = ldiskfs_add_dot_dotdot(oth->ot_handle, parent_dir, + inode, dot_ldp, dot_dot_ldp); + if (result == 0) + obj->oo_compat_dotdot_created = 1; + + return result; } @@ -3287,40 +3300,39 @@ static int osd_ea_add_rec(const struct lu_env *env, struct osd_object *pobj, struct inode *cinode, const char *name, const struct dt_rec *fid, struct thandle *th) { - struct osd_thread_info *info = osd_oti_get(env); - struct htree_lock *hlock; - int rc; + struct osd_thread_info *info = osd_oti_get(env); + struct htree_lock *hlock; + int rc; - hlock = pobj->oo_hl_head != NULL ? info->oti_hlock : NULL; + hlock = pobj->oo_hl_head != NULL ? info->oti_hlock : NULL; - if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && - name[2] =='\0'))) { - if (hlock != NULL) { - ldiskfs_htree_lock(hlock, pobj->oo_hl_head, - pobj->oo_inode, 0); - } else { + if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && + name[2] == '\0'))) { + if (hlock != NULL) { + ldiskfs_htree_lock(hlock, pobj->oo_hl_head, + pobj->oo_inode, 0); + } else { down_write(&pobj->oo_ext_idx_sem); - } - rc = osd_add_dot_dotdot(info, pobj, cinode, name, - (struct dt_rec *)lu_object_fid(&pobj->oo_dt.do_lu), - fid, th); - } else { - if (hlock != NULL) { - ldiskfs_htree_lock(hlock, pobj->oo_hl_head, - pobj->oo_inode, LDISKFS_HLOCK_ADD); - } else { + } + rc = osd_add_dot_dotdot(info, pobj, cinode, name, + (struct dt_rec *)lu_object_fid(&pobj->oo_dt.do_lu), + fid, th); + } else { + if (hlock != NULL) { + ldiskfs_htree_lock(hlock, pobj->oo_hl_head, + pobj->oo_inode, LDISKFS_HLOCK_ADD); + } else { down_write(&pobj->oo_ext_idx_sem); - } + } - rc = __osd_ea_add_rec(info, pobj, cinode, name, fid, - hlock, th); - } - if (hlock != NULL) - ldiskfs_htree_unlock(hlock); - else + rc = osd_ea_add_norm(info, pobj, cinode, name, fid, hlock, th); + } + if (hlock != NULL) + ldiskfs_htree_unlock(hlock); + else up_write(&pobj->oo_ext_idx_sem); - return rc; + return rc; } static void -- 1.7.11.5