Commit 5b6a3a2b authored by Mark Fasheh's avatar Mark Fasheh
Browse files

ocfs2: Write support for directories with inline data



Create all new directories with OCFS2_INLINE_DATA_FL and the inline data
bytes formatted as an empty directory. Inode size field reflects the actual
amount of inline data available, which makes searching for dirent space
very similar to the regular directory search.

Inline-data directories are automatically pushed out to extents on any
insert request which is too large for the available space.
Signed-off-by: default avatarMark Fasheh <mark.fasheh@oracle.com>
Reviewed-by: default avatarJoel Becker <joel.becker@oracle.com>
parent 23193e51
......@@ -5835,6 +5835,15 @@ static void ocfs2_zero_dinode_id2(struct inode *inode, struct ocfs2_dinode *di)
memset(&di->id2, 0, blocksize - offsetof(struct ocfs2_dinode, id2));
}
void ocfs2_dinode_new_extent_list(struct inode *inode,
struct ocfs2_dinode *di)
{
ocfs2_zero_dinode_id2(inode, di);
di->id2.i_list.l_tree_depth = 0;
di->id2.i_list.l_next_free_rec = 0;
di->id2.i_list.l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(inode->i_sb));
}
void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di)
{
struct ocfs2_inode_info *oi = OCFS2_I(inode);
......@@ -5863,7 +5872,6 @@ int ocfs2_convert_inline_data_to_extents(struct inode *inode,
struct ocfs2_inode_info *oi = OCFS2_I(inode);
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
struct ocfs2_extent_list *el = &di->id2.i_list;
struct ocfs2_alloc_context *data_ac = NULL;
struct page **pages = NULL;
loff_t end = osb->s_clustersize;
......@@ -5956,11 +5964,7 @@ int ocfs2_convert_inline_data_to_extents(struct inode *inode,
di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
spin_unlock(&oi->ip_lock);
ocfs2_zero_dinode_id2(inode, di);
el->l_tree_depth = 0;
el->l_next_free_rec = 0;
el->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(inode->i_sb));
ocfs2_dinode_new_extent_list(inode, di);
ocfs2_journal_dirty(handle, di_bh);
......
......@@ -62,6 +62,7 @@ static inline int ocfs2_extend_meta_needed(struct ocfs2_dinode *fe)
return le16_to_cpu(fe->id2.i_list.l_tree_depth) + 2;
}
void ocfs2_dinode_new_extent_list(struct inode *inode, struct ocfs2_dinode *di);
void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di);
int ocfs2_convert_inline_data_to_extents(struct inode *inode,
struct buffer_head *di_bh);
......
This diff is collapsed.
......@@ -250,9 +250,8 @@ static int ocfs2_mknod(struct inode *dir,
goto leave;
}
/* are we making a directory? If so, reserve a cluster for his
* 1st extent. */
if (S_ISDIR(mode)) {
/* Reserve a cluster if creating an extent based directory. */
if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) {
status = ocfs2_reserve_clusters(osb, 1, &data_ac);
if (status < 0) {
if (status != -ENOSPC)
......@@ -449,10 +448,21 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
cpu_to_le32(CURRENT_TIME.tv_nsec);
fe->i_dtime = 0;
fel = &fe->id2.i_list;
fel->l_tree_depth = 0;
fel->l_next_free_rec = 0;
fel->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(osb->sb));
/*
* If supported, directories start with inline data.
*/
if (S_ISDIR(mode) && ocfs2_supports_inline_data(osb)) {
u16 feat = le16_to_cpu(fe->i_dyn_features);
fe->i_dyn_features = cpu_to_le16(feat | OCFS2_INLINE_DATA_FL);
fe->id2.i_data.id_count = cpu_to_le16(ocfs2_max_inline_data(osb->sb));
} else {
fel = &fe->id2.i_list;
fel->l_tree_depth = 0;
fel->l_next_free_rec = 0;
fel->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(osb->sb));
}
status = ocfs2_journal_dirty(handle, *new_fe_bh);
if (status < 0) {
......@@ -950,7 +960,7 @@ static int ocfs2_rename(struct inode *old_dir,
struct buffer_head *old_inode_bh = NULL;
struct buffer_head *insert_entry_bh = NULL;
struct ocfs2_super *osb = NULL;
u64 newfe_blkno;
u64 newfe_blkno, old_de_ino;
handle_t *handle = NULL;
struct buffer_head *old_dir_bh = NULL;
struct buffer_head *new_dir_bh = NULL;
......@@ -1061,12 +1071,13 @@ static int ocfs2_rename(struct inode *old_dir,
}
}
status = -ENOENT;
old_de_bh = ocfs2_find_entry(old_dentry->d_name.name,
old_dentry->d_name.len,
old_dir, &old_de);
if (!old_de_bh)
status = ocfs2_lookup_ino_from_name(old_dir, old_dentry->d_name.name,
old_dentry->d_name.len,
&old_de_ino);
if (status) {
status = -ENOENT;
goto bail;
}
/*
* Check for inode number is _not_ due to possible IO errors.
......@@ -1074,8 +1085,10 @@ static int ocfs2_rename(struct inode *old_dir,
* and merrily kill the link to whatever was created under the
* same name. Goodbye sticky bit ;-<
*/
if (le64_to_cpu(old_de->inode) != OCFS2_I(old_inode)->ip_blkno)
if (old_de_ino != OCFS2_I(old_inode)->ip_blkno) {
status = -ENOENT;
goto bail;
}
/* check if the target already exists (in which case we need
* to delete it */
......@@ -1250,7 +1263,21 @@ static int ocfs2_rename(struct inode *old_dir,
} else
mlog_errno(status);
/* now that the name has been added to new_dir, remove the old name */
/*
* Now that the name has been added to new_dir, remove the old name.
*
* We don't keep any directory entry context around until now
* because the insert might have changed the type of directory
* we're dealing with.
*/
old_de_bh = ocfs2_find_entry(old_dentry->d_name.name,
old_dentry->d_name.len,
old_dir, &old_de);
if (!old_de_bh) {
status = -EIO;
goto bail;
}
status = ocfs2_delete_entry(handle, old_dir, old_de, old_de_bh);
if (status < 0) {
mlog_errno(status);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment