diff options
Diffstat (limited to 'fs/xfs/xfs_dir2_sf.c')
-rw-r--r-- | fs/xfs/xfs_dir2_sf.c | 58 |
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); |
262 | out: | 272 | out: |
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 | ||