diff options
| -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 | ||
