aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_dir2_sf.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_dir2_sf.c')
-rw-r--r--fs/xfs/xfs_dir2_sf.c58
1 files changed, 34 insertions, 24 deletions
diff --git a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c
index aafc6e46cb58..3725fb1b902b 100644
--- a/fs/xfs/xfs_dir2_sf.c
+++ b/fs/xfs/xfs_dir2_sf.c
@@ -170,6 +170,7 @@ xfs_dir2_block_to_sf(
170 char *ptr; /* current data pointer */ 170 char *ptr; /* current data pointer */
171 xfs_dir2_sf_entry_t *sfep; /* shortform entry */ 171 xfs_dir2_sf_entry_t *sfep; /* shortform entry */
172 xfs_dir2_sf_hdr_t *sfp; /* shortform directory header */ 172 xfs_dir2_sf_hdr_t *sfp; /* shortform directory header */
173 xfs_dir2_sf_hdr_t *dst; /* temporary data buffer */
173 174
174 trace_xfs_dir2_block_to_sf(args); 175 trace_xfs_dir2_block_to_sf(args);
175 176
@@ -177,35 +178,20 @@ xfs_dir2_block_to_sf(
177 mp = dp->i_mount; 178 mp = dp->i_mount;
178 179
179 /* 180 /*
180 * Make a copy of the block data, so we can shrink the inode 181 * allocate a temporary destination buffer the size of the inode
181 * and add local data. 182 * to format the data into. Once we have formatted the data, we
183 * can free the block and copy the formatted data into the inode literal
184 * area.
182 */ 185 */
183 hdr = kmem_alloc(mp->m_dirblksize, KM_SLEEP); 186 dst = kmem_alloc(mp->m_sb.sb_inodesize, KM_SLEEP);
184 memcpy(hdr, bp->b_addr, mp->m_dirblksize); 187 hdr = bp->b_addr;
185 logflags = XFS_ILOG_CORE;
186 if ((error = xfs_dir2_shrink_inode(args, mp->m_dirdatablk, bp))) {
187 ASSERT(error != ENOSPC);
188 goto out;
189 }
190 188
191 /* 189 /*
192 * The buffer is now unconditionally gone, whether
193 * xfs_dir2_shrink_inode worked or not.
194 *
195 * Convert the inode to local format.
196 */
197 dp->i_df.if_flags &= ~XFS_IFEXTENTS;
198 dp->i_df.if_flags |= XFS_IFINLINE;
199 dp->i_d.di_format = XFS_DINODE_FMT_LOCAL;
200 ASSERT(dp->i_df.if_bytes == 0);
201 xfs_idata_realloc(dp, size, XFS_DATA_FORK);
202 logflags |= XFS_ILOG_DDATA;
203 /*
204 * Copy the header into the newly allocate local space. 190 * Copy the header into the newly allocate local space.
205 */ 191 */
206 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 192 sfp = (xfs_dir2_sf_hdr_t *)dst;
207 memcpy(sfp, sfhp, xfs_dir2_sf_hdr_size(sfhp->i8count)); 193 memcpy(sfp, sfhp, xfs_dir2_sf_hdr_size(sfhp->i8count));
208 dp->i_d.di_size = size; 194
209 /* 195 /*
210 * Set up to loop over the block's entries. 196 * Set up to loop over the block's entries.
211 */ 197 */
@@ -258,10 +244,34 @@ xfs_dir2_block_to_sf(
258 ptr += dp->d_ops->data_entsize(dep->namelen); 244 ptr += dp->d_ops->data_entsize(dep->namelen);
259 } 245 }
260 ASSERT((char *)sfep - (char *)sfp == size); 246 ASSERT((char *)sfep - (char *)sfp == size);
247
248 /* now we are done with the block, we can shrink the inode */
249 logflags = XFS_ILOG_CORE;
250 error = xfs_dir2_shrink_inode(args, mp->m_dirdatablk, bp);
251 if (error) {
252 ASSERT(error != ENOSPC);
253 goto out;
254 }
255
256 /*
257 * The buffer is now unconditionally gone, whether
258 * xfs_dir2_shrink_inode worked or not.
259 *
260 * Convert the inode to local format and copy the data in.
261 */
262 dp->i_df.if_flags &= ~XFS_IFEXTENTS;
263 dp->i_df.if_flags |= XFS_IFINLINE;
264 dp->i_d.di_format = XFS_DINODE_FMT_LOCAL;
265 ASSERT(dp->i_df.if_bytes == 0);
266 xfs_idata_realloc(dp, size, XFS_DATA_FORK);
267
268 logflags |= XFS_ILOG_DDATA;
269 memcpy(dp->i_df.if_u1.if_data, dst, size);
270 dp->i_d.di_size = size;
261 xfs_dir2_sf_check(args); 271 xfs_dir2_sf_check(args);
262out: 272out:
263 xfs_trans_log_inode(args->trans, dp, logflags); 273 xfs_trans_log_inode(args->trans, dp, logflags);
264 kmem_free(hdr); 274 kmem_free(dst);
265 return error; 275 return error;
266} 276}
267 277