diff options
Diffstat (limited to 'fs/xfs/xfs_attr.c')
-rw-r--r-- | fs/xfs/xfs_attr.c | 80 |
1 files changed, 48 insertions, 32 deletions
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index 78de80e3caa2..ffa634d1c18c 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c | |||
@@ -194,6 +194,46 @@ xfs_attr_get( | |||
194 | return(error); | 194 | return(error); |
195 | } | 195 | } |
196 | 196 | ||
197 | /* | ||
198 | * Calculate how many blocks we need for the new attribute, | ||
199 | */ | ||
200 | int | ||
201 | xfs_attr_calc_size( | ||
202 | struct xfs_inode *ip, | ||
203 | int namelen, | ||
204 | int valuelen, | ||
205 | int *local) | ||
206 | { | ||
207 | struct xfs_mount *mp = ip->i_mount; | ||
208 | int size; | ||
209 | int nblks; | ||
210 | |||
211 | /* | ||
212 | * Determine space new attribute will use, and if it would be | ||
213 | * "local" or "remote" (note: local != inline). | ||
214 | */ | ||
215 | size = xfs_attr_leaf_newentsize(namelen, valuelen, | ||
216 | mp->m_sb.sb_blocksize, local); | ||
217 | |||
218 | nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); | ||
219 | if (*local) { | ||
220 | if (size > (mp->m_sb.sb_blocksize >> 1)) { | ||
221 | /* Double split possible */ | ||
222 | nblks *= 2; | ||
223 | } | ||
224 | } else { | ||
225 | /* | ||
226 | * Out of line attribute, cannot double split, but | ||
227 | * make room for the attribute value itself. | ||
228 | */ | ||
229 | uint dblocks = XFS_B_TO_FSB(mp, valuelen); | ||
230 | nblks += dblocks; | ||
231 | nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK); | ||
232 | } | ||
233 | |||
234 | return nblks; | ||
235 | } | ||
236 | |||
197 | STATIC int | 237 | STATIC int |
198 | xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, | 238 | xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, |
199 | char *value, int valuelen, int flags) | 239 | char *value, int valuelen, int flags) |
@@ -202,10 +242,9 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, | |||
202 | xfs_fsblock_t firstblock; | 242 | xfs_fsblock_t firstblock; |
203 | xfs_bmap_free_t flist; | 243 | xfs_bmap_free_t flist; |
204 | int error, err2, committed; | 244 | int error, err2, committed; |
205 | int local, size; | ||
206 | uint nblks; | ||
207 | xfs_mount_t *mp = dp->i_mount; | 245 | xfs_mount_t *mp = dp->i_mount; |
208 | int rsvd = (flags & ATTR_ROOT) != 0; | 246 | int rsvd = (flags & ATTR_ROOT) != 0; |
247 | int local; | ||
209 | 248 | ||
210 | /* | 249 | /* |
211 | * Attach the dquots to the inode. | 250 | * Attach the dquots to the inode. |
@@ -241,30 +280,8 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, | |||
241 | args.whichfork = XFS_ATTR_FORK; | 280 | args.whichfork = XFS_ATTR_FORK; |
242 | args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; | 281 | args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; |
243 | 282 | ||
244 | /* | ||
245 | * Determine space new attribute will use, and if it would be | ||
246 | * "local" or "remote" (note: local != inline). | ||
247 | */ | ||
248 | size = xfs_attr_leaf_newentsize(name->len, valuelen, | ||
249 | mp->m_sb.sb_blocksize, &local); | ||
250 | |||
251 | nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); | ||
252 | if (local) { | ||
253 | if (size > (mp->m_sb.sb_blocksize >> 1)) { | ||
254 | /* Double split possible */ | ||
255 | nblks <<= 1; | ||
256 | } | ||
257 | } else { | ||
258 | uint dblocks = XFS_B_TO_FSB(mp, valuelen); | ||
259 | /* Out of line attribute, cannot double split, but make | ||
260 | * room for the attribute value itself. | ||
261 | */ | ||
262 | nblks += dblocks; | ||
263 | nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK); | ||
264 | } | ||
265 | |||
266 | /* Size is now blocks for attribute data */ | 283 | /* Size is now blocks for attribute data */ |
267 | args.total = nblks; | 284 | args.total = xfs_attr_calc_size(dp, name->len, valuelen, &local); |
268 | 285 | ||
269 | /* | 286 | /* |
270 | * Start our first transaction of the day. | 287 | * Start our first transaction of the day. |
@@ -286,18 +303,17 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, | |||
286 | if (rsvd) | 303 | if (rsvd) |
287 | args.trans->t_flags |= XFS_TRANS_RESERVE; | 304 | args.trans->t_flags |= XFS_TRANS_RESERVE; |
288 | 305 | ||
289 | if ((error = xfs_trans_reserve(args.trans, (uint) nblks, | 306 | if ((error = xfs_trans_reserve(args.trans, args.total, |
290 | XFS_ATTRSET_LOG_RES(mp, nblks), | 307 | XFS_ATTRSET_LOG_RES(mp, args.total), 0, |
291 | 0, XFS_TRANS_PERM_LOG_RES, | 308 | XFS_TRANS_PERM_LOG_RES, XFS_ATTRSET_LOG_COUNT))) { |
292 | XFS_ATTRSET_LOG_COUNT))) { | ||
293 | xfs_trans_cancel(args.trans, 0); | 309 | xfs_trans_cancel(args.trans, 0); |
294 | return(error); | 310 | return(error); |
295 | } | 311 | } |
296 | xfs_ilock(dp, XFS_ILOCK_EXCL); | 312 | xfs_ilock(dp, XFS_ILOCK_EXCL); |
297 | 313 | ||
298 | error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, args.trans, dp, nblks, 0, | 314 | error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, args.trans, dp, args.total, 0, |
299 | rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : | 315 | rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : |
300 | XFS_QMOPT_RES_REGBLKS); | 316 | XFS_QMOPT_RES_REGBLKS); |
301 | if (error) { | 317 | if (error) { |
302 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 318 | xfs_iunlock(dp, XFS_ILOCK_EXCL); |
303 | xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES); | 319 | xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES); |