diff options
Diffstat (limited to 'fs/xfs/xfs_bmap.c')
-rw-r--r-- | fs/xfs/xfs_bmap.c | 412 |
1 files changed, 251 insertions, 161 deletions
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index e415a4698e9c..70625e577c70 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
@@ -2146,13 +2146,176 @@ xfs_bmap_add_extent_hole_real( | |||
2146 | return 0; /* keep gcc quite */ | 2146 | return 0; /* keep gcc quite */ |
2147 | } | 2147 | } |
2148 | 2148 | ||
2149 | /* | ||
2150 | * Adjust the size of the new extent based on di_extsize and rt extsize. | ||
2151 | */ | ||
2152 | STATIC int | ||
2153 | xfs_bmap_extsize_align( | ||
2154 | xfs_mount_t *mp, | ||
2155 | xfs_bmbt_irec_t *gotp, /* next extent pointer */ | ||
2156 | xfs_bmbt_irec_t *prevp, /* previous extent pointer */ | ||
2157 | xfs_extlen_t extsz, /* align to this extent size */ | ||
2158 | int rt, /* is this a realtime inode? */ | ||
2159 | int eof, /* is extent at end-of-file? */ | ||
2160 | int delay, /* creating delalloc extent? */ | ||
2161 | int convert, /* overwriting unwritten extent? */ | ||
2162 | xfs_fileoff_t *offp, /* in/out: aligned offset */ | ||
2163 | xfs_extlen_t *lenp) /* in/out: aligned length */ | ||
2164 | { | ||
2165 | xfs_fileoff_t orig_off; /* original offset */ | ||
2166 | xfs_extlen_t orig_alen; /* original length */ | ||
2167 | xfs_fileoff_t orig_end; /* original off+len */ | ||
2168 | xfs_fileoff_t nexto; /* next file offset */ | ||
2169 | xfs_fileoff_t prevo; /* previous file offset */ | ||
2170 | xfs_fileoff_t align_off; /* temp for offset */ | ||
2171 | xfs_extlen_t align_alen; /* temp for length */ | ||
2172 | xfs_extlen_t temp; /* temp for calculations */ | ||
2173 | |||
2174 | if (convert) | ||
2175 | return 0; | ||
2176 | |||
2177 | orig_off = align_off = *offp; | ||
2178 | orig_alen = align_alen = *lenp; | ||
2179 | orig_end = orig_off + orig_alen; | ||
2180 | |||
2181 | /* | ||
2182 | * If this request overlaps an existing extent, then don't | ||
2183 | * attempt to perform any additional alignment. | ||
2184 | */ | ||
2185 | if (!delay && !eof && | ||
2186 | (orig_off >= gotp->br_startoff) && | ||
2187 | (orig_end <= gotp->br_startoff + gotp->br_blockcount)) { | ||
2188 | return 0; | ||
2189 | } | ||
2190 | |||
2191 | /* | ||
2192 | * If the file offset is unaligned vs. the extent size | ||
2193 | * we need to align it. This will be possible unless | ||
2194 | * the file was previously written with a kernel that didn't | ||
2195 | * perform this alignment, or if a truncate shot us in the | ||
2196 | * foot. | ||
2197 | */ | ||
2198 | temp = do_mod(orig_off, extsz); | ||
2199 | if (temp) { | ||
2200 | align_alen += temp; | ||
2201 | align_off -= temp; | ||
2202 | } | ||
2203 | /* | ||
2204 | * Same adjustment for the end of the requested area. | ||
2205 | */ | ||
2206 | if ((temp = (align_alen % extsz))) { | ||
2207 | align_alen += extsz - temp; | ||
2208 | } | ||
2209 | /* | ||
2210 | * If the previous block overlaps with this proposed allocation | ||
2211 | * then move the start forward without adjusting the length. | ||
2212 | */ | ||
2213 | if (prevp->br_startoff != NULLFILEOFF) { | ||
2214 | if (prevp->br_startblock == HOLESTARTBLOCK) | ||
2215 | prevo = prevp->br_startoff; | ||
2216 | else | ||
2217 | prevo = prevp->br_startoff + prevp->br_blockcount; | ||
2218 | } else | ||
2219 | prevo = 0; | ||
2220 | if (align_off != orig_off && align_off < prevo) | ||
2221 | align_off = prevo; | ||
2222 | /* | ||
2223 | * If the next block overlaps with this proposed allocation | ||
2224 | * then move the start back without adjusting the length, | ||
2225 | * but not before offset 0. | ||
2226 | * This may of course make the start overlap previous block, | ||
2227 | * and if we hit the offset 0 limit then the next block | ||
2228 | * can still overlap too. | ||
2229 | */ | ||
2230 | if (!eof && gotp->br_startoff != NULLFILEOFF) { | ||
2231 | if ((delay && gotp->br_startblock == HOLESTARTBLOCK) || | ||
2232 | (!delay && gotp->br_startblock == DELAYSTARTBLOCK)) | ||
2233 | nexto = gotp->br_startoff + gotp->br_blockcount; | ||
2234 | else | ||
2235 | nexto = gotp->br_startoff; | ||
2236 | } else | ||
2237 | nexto = NULLFILEOFF; | ||
2238 | if (!eof && | ||
2239 | align_off + align_alen != orig_end && | ||
2240 | align_off + align_alen > nexto) | ||
2241 | align_off = nexto > align_alen ? nexto - align_alen : 0; | ||
2242 | /* | ||
2243 | * If we're now overlapping the next or previous extent that | ||
2244 | * means we can't fit an extsz piece in this hole. Just move | ||
2245 | * the start forward to the first valid spot and set | ||
2246 | * the length so we hit the end. | ||
2247 | */ | ||
2248 | if (align_off != orig_off && align_off < prevo) | ||
2249 | align_off = prevo; | ||
2250 | if (align_off + align_alen != orig_end && | ||
2251 | align_off + align_alen > nexto && | ||
2252 | nexto != NULLFILEOFF) { | ||
2253 | ASSERT(nexto > prevo); | ||
2254 | align_alen = nexto - align_off; | ||
2255 | } | ||
2256 | |||
2257 | /* | ||
2258 | * If realtime, and the result isn't a multiple of the realtime | ||
2259 | * extent size we need to remove blocks until it is. | ||
2260 | */ | ||
2261 | if (rt && (temp = (align_alen % mp->m_sb.sb_rextsize))) { | ||
2262 | /* | ||
2263 | * We're not covering the original request, or | ||
2264 | * we won't be able to once we fix the length. | ||
2265 | */ | ||
2266 | if (orig_off < align_off || | ||
2267 | orig_end > align_off + align_alen || | ||
2268 | align_alen - temp < orig_alen) | ||
2269 | return XFS_ERROR(EINVAL); | ||
2270 | /* | ||
2271 | * Try to fix it by moving the start up. | ||
2272 | */ | ||
2273 | if (align_off + temp <= orig_off) { | ||
2274 | align_alen -= temp; | ||
2275 | align_off += temp; | ||
2276 | } | ||
2277 | /* | ||
2278 | * Try to fix it by moving the end in. | ||
2279 | */ | ||
2280 | else if (align_off + align_alen - temp >= orig_end) | ||
2281 | align_alen -= temp; | ||
2282 | /* | ||
2283 | * Set the start to the minimum then trim the length. | ||
2284 | */ | ||
2285 | else { | ||
2286 | align_alen -= orig_off - align_off; | ||
2287 | align_off = orig_off; | ||
2288 | align_alen -= align_alen % mp->m_sb.sb_rextsize; | ||
2289 | } | ||
2290 | /* | ||
2291 | * Result doesn't cover the request, fail it. | ||
2292 | */ | ||
2293 | if (orig_off < align_off || orig_end > align_off + align_alen) | ||
2294 | return XFS_ERROR(EINVAL); | ||
2295 | } else { | ||
2296 | ASSERT(orig_off >= align_off); | ||
2297 | ASSERT(orig_end <= align_off + align_alen); | ||
2298 | } | ||
2299 | |||
2300 | #ifdef DEBUG | ||
2301 | if (!eof && gotp->br_startoff != NULLFILEOFF) | ||
2302 | ASSERT(align_off + align_alen <= gotp->br_startoff); | ||
2303 | if (prevp->br_startoff != NULLFILEOFF) | ||
2304 | ASSERT(align_off >= prevp->br_startoff + prevp->br_blockcount); | ||
2305 | #endif | ||
2306 | |||
2307 | *lenp = align_alen; | ||
2308 | *offp = align_off; | ||
2309 | return 0; | ||
2310 | } | ||
2311 | |||
2149 | #define XFS_ALLOC_GAP_UNITS 4 | 2312 | #define XFS_ALLOC_GAP_UNITS 4 |
2150 | 2313 | ||
2151 | /* | 2314 | /* |
2152 | * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file. | 2315 | * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file. |
2153 | * It figures out where to ask the underlying allocator to put the new extent. | 2316 | * It figures out where to ask the underlying allocator to put the new extent. |
2154 | */ | 2317 | */ |
2155 | STATIC int /* error */ | 2318 | STATIC int |
2156 | xfs_bmap_alloc( | 2319 | xfs_bmap_alloc( |
2157 | xfs_bmalloca_t *ap) /* bmap alloc argument struct */ | 2320 | xfs_bmalloca_t *ap) /* bmap alloc argument struct */ |
2158 | { | 2321 | { |
@@ -2163,10 +2326,10 @@ xfs_bmap_alloc( | |||
2163 | xfs_mount_t *mp; /* mount point structure */ | 2326 | xfs_mount_t *mp; /* mount point structure */ |
2164 | int nullfb; /* true if ap->firstblock isn't set */ | 2327 | int nullfb; /* true if ap->firstblock isn't set */ |
2165 | int rt; /* true if inode is realtime */ | 2328 | int rt; /* true if inode is realtime */ |
2166 | #ifdef __KERNEL__ | 2329 | xfs_extlen_t prod = 0; /* product factor for allocators */ |
2167 | xfs_extlen_t prod=0; /* product factor for allocators */ | 2330 | xfs_extlen_t ralen = 0; /* realtime allocation length */ |
2168 | xfs_extlen_t ralen=0; /* realtime allocation length */ | 2331 | xfs_extlen_t align; /* minimum allocation alignment */ |
2169 | #endif | 2332 | xfs_rtblock_t rtx; |
2170 | 2333 | ||
2171 | #define ISVALID(x,y) \ | 2334 | #define ISVALID(x,y) \ |
2172 | (rt ? \ | 2335 | (rt ? \ |
@@ -2182,125 +2345,25 @@ xfs_bmap_alloc( | |||
2182 | nullfb = ap->firstblock == NULLFSBLOCK; | 2345 | nullfb = ap->firstblock == NULLFSBLOCK; |
2183 | rt = XFS_IS_REALTIME_INODE(ap->ip) && ap->userdata; | 2346 | rt = XFS_IS_REALTIME_INODE(ap->ip) && ap->userdata; |
2184 | fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->firstblock); | 2347 | fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->firstblock); |
2185 | #ifdef __KERNEL__ | ||
2186 | if (rt) { | 2348 | if (rt) { |
2187 | xfs_extlen_t extsz; /* file extent size for rt */ | 2349 | align = ap->ip->i_d.di_extsize ? |
2188 | xfs_fileoff_t nexto; /* next file offset */ | 2350 | ap->ip->i_d.di_extsize : mp->m_sb.sb_rextsize; |
2189 | xfs_extlen_t orig_alen; /* original ap->alen */ | 2351 | /* Set prod to match the extent size */ |
2190 | xfs_fileoff_t orig_end; /* original off+len */ | 2352 | prod = align / mp->m_sb.sb_rextsize; |
2191 | xfs_fileoff_t orig_off; /* original ap->off */ | 2353 | |
2192 | xfs_extlen_t mod_off; /* modulus calculations */ | 2354 | error = xfs_bmap_extsize_align(mp, ap->gotp, ap->prevp, |
2193 | xfs_fileoff_t prevo; /* previous file offset */ | 2355 | align, rt, ap->eof, 0, |
2194 | xfs_rtblock_t rtx; /* realtime extent number */ | 2356 | ap->conv, &ap->off, &ap->alen); |
2195 | xfs_extlen_t temp; /* temp for rt calculations */ | 2357 | if (error) |
2196 | 2358 | return error; | |
2197 | /* | 2359 | ASSERT(ap->alen); |
2198 | * Set prod to match the realtime extent size. | ||
2199 | */ | ||
2200 | if (!(extsz = ap->ip->i_d.di_extsize)) | ||
2201 | extsz = mp->m_sb.sb_rextsize; | ||
2202 | prod = extsz / mp->m_sb.sb_rextsize; | ||
2203 | orig_off = ap->off; | ||
2204 | orig_alen = ap->alen; | ||
2205 | orig_end = orig_off + orig_alen; | ||
2206 | /* | ||
2207 | * If the file offset is unaligned vs. the extent size | ||
2208 | * we need to align it. This will be possible unless | ||
2209 | * the file was previously written with a kernel that didn't | ||
2210 | * perform this alignment. | ||
2211 | */ | ||
2212 | mod_off = do_mod(orig_off, extsz); | ||
2213 | if (mod_off) { | ||
2214 | ap->alen += mod_off; | ||
2215 | ap->off -= mod_off; | ||
2216 | } | ||
2217 | /* | ||
2218 | * Same adjustment for the end of the requested area. | ||
2219 | */ | ||
2220 | if ((temp = (ap->alen % extsz))) | ||
2221 | ap->alen += extsz - temp; | ||
2222 | /* | ||
2223 | * If the previous block overlaps with this proposed allocation | ||
2224 | * then move the start forward without adjusting the length. | ||
2225 | */ | ||
2226 | prevo = | ||
2227 | ap->prevp->br_startoff == NULLFILEOFF ? | ||
2228 | 0 : | ||
2229 | (ap->prevp->br_startoff + | ||
2230 | ap->prevp->br_blockcount); | ||
2231 | if (ap->off != orig_off && ap->off < prevo) | ||
2232 | ap->off = prevo; | ||
2233 | /* | ||
2234 | * If the next block overlaps with this proposed allocation | ||
2235 | * then move the start back without adjusting the length, | ||
2236 | * but not before offset 0. | ||
2237 | * This may of course make the start overlap previous block, | ||
2238 | * and if we hit the offset 0 limit then the next block | ||
2239 | * can still overlap too. | ||
2240 | */ | ||
2241 | nexto = (ap->eof || ap->gotp->br_startoff == NULLFILEOFF) ? | ||
2242 | NULLFILEOFF : ap->gotp->br_startoff; | ||
2243 | if (!ap->eof && | ||
2244 | ap->off + ap->alen != orig_end && | ||
2245 | ap->off + ap->alen > nexto) | ||
2246 | ap->off = nexto > ap->alen ? nexto - ap->alen : 0; | ||
2247 | /* | ||
2248 | * If we're now overlapping the next or previous extent that | ||
2249 | * means we can't fit an extsz piece in this hole. Just move | ||
2250 | * the start forward to the first valid spot and set | ||
2251 | * the length so we hit the end. | ||
2252 | */ | ||
2253 | if ((ap->off != orig_off && ap->off < prevo) || | ||
2254 | (ap->off + ap->alen != orig_end && | ||
2255 | ap->off + ap->alen > nexto)) { | ||
2256 | ap->off = prevo; | ||
2257 | ap->alen = nexto - prevo; | ||
2258 | } | ||
2259 | /* | ||
2260 | * If the result isn't a multiple of rtextents we need to | ||
2261 | * remove blocks until it is. | ||
2262 | */ | ||
2263 | if ((temp = (ap->alen % mp->m_sb.sb_rextsize))) { | ||
2264 | /* | ||
2265 | * We're not covering the original request, or | ||
2266 | * we won't be able to once we fix the length. | ||
2267 | */ | ||
2268 | if (orig_off < ap->off || | ||
2269 | orig_end > ap->off + ap->alen || | ||
2270 | ap->alen - temp < orig_alen) | ||
2271 | return XFS_ERROR(EINVAL); | ||
2272 | /* | ||
2273 | * Try to fix it by moving the start up. | ||
2274 | */ | ||
2275 | if (ap->off + temp <= orig_off) { | ||
2276 | ap->alen -= temp; | ||
2277 | ap->off += temp; | ||
2278 | } | ||
2279 | /* | ||
2280 | * Try to fix it by moving the end in. | ||
2281 | */ | ||
2282 | else if (ap->off + ap->alen - temp >= orig_end) | ||
2283 | ap->alen -= temp; | ||
2284 | /* | ||
2285 | * Set the start to the minimum then trim the length. | ||
2286 | */ | ||
2287 | else { | ||
2288 | ap->alen -= orig_off - ap->off; | ||
2289 | ap->off = orig_off; | ||
2290 | ap->alen -= ap->alen % mp->m_sb.sb_rextsize; | ||
2291 | } | ||
2292 | /* | ||
2293 | * Result doesn't cover the request, fail it. | ||
2294 | */ | ||
2295 | if (orig_off < ap->off || orig_end > ap->off + ap->alen) | ||
2296 | return XFS_ERROR(EINVAL); | ||
2297 | } | ||
2298 | ASSERT(ap->alen % mp->m_sb.sb_rextsize == 0); | 2360 | ASSERT(ap->alen % mp->m_sb.sb_rextsize == 0); |
2361 | |||
2299 | /* | 2362 | /* |
2300 | * If the offset & length are not perfectly aligned | 2363 | * If the offset & length are not perfectly aligned |
2301 | * then kill prod, it will just get us in trouble. | 2364 | * then kill prod, it will just get us in trouble. |
2302 | */ | 2365 | */ |
2303 | if (do_mod(ap->off, extsz) || ap->alen % extsz) | 2366 | if (do_mod(ap->off, align) || ap->alen % align) |
2304 | prod = 1; | 2367 | prod = 1; |
2305 | /* | 2368 | /* |
2306 | * Set ralen to be the actual requested length in rtextents. | 2369 | * Set ralen to be the actual requested length in rtextents. |
@@ -2326,15 +2389,24 @@ xfs_bmap_alloc( | |||
2326 | ap->rval = rtx * mp->m_sb.sb_rextsize; | 2389 | ap->rval = rtx * mp->m_sb.sb_rextsize; |
2327 | } else | 2390 | } else |
2328 | ap->rval = 0; | 2391 | ap->rval = 0; |
2392 | } else { | ||
2393 | align = (ap->userdata && ap->ip->i_d.di_extsize && | ||
2394 | (ap->ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE)) ? | ||
2395 | ap->ip->i_d.di_extsize : 0; | ||
2396 | if (unlikely(align)) { | ||
2397 | error = xfs_bmap_extsize_align(mp, ap->gotp, ap->prevp, | ||
2398 | align, rt, | ||
2399 | ap->eof, 0, ap->conv, | ||
2400 | &ap->off, &ap->alen); | ||
2401 | ASSERT(!error); | ||
2402 | ASSERT(ap->alen); | ||
2403 | } | ||
2404 | if (nullfb) | ||
2405 | ap->rval = XFS_INO_TO_FSB(mp, ap->ip->i_ino); | ||
2406 | else | ||
2407 | ap->rval = ap->firstblock; | ||
2329 | } | 2408 | } |
2330 | #else | 2409 | |
2331 | if (rt) | ||
2332 | ap->rval = 0; | ||
2333 | #endif /* __KERNEL__ */ | ||
2334 | else if (nullfb) | ||
2335 | ap->rval = XFS_INO_TO_FSB(mp, ap->ip->i_ino); | ||
2336 | else | ||
2337 | ap->rval = ap->firstblock; | ||
2338 | /* | 2410 | /* |
2339 | * If allocating at eof, and there's a previous real block, | 2411 | * If allocating at eof, and there's a previous real block, |
2340 | * try to use it's last block as our starting point. | 2412 | * try to use it's last block as our starting point. |
@@ -2598,11 +2670,12 @@ xfs_bmap_alloc( | |||
2598 | args.total = ap->total; | 2670 | args.total = ap->total; |
2599 | args.minlen = ap->minlen; | 2671 | args.minlen = ap->minlen; |
2600 | } | 2672 | } |
2601 | if (ap->ip->i_d.di_extsize) { | 2673 | if (unlikely(ap->userdata && ap->ip->i_d.di_extsize && |
2674 | (ap->ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE))) { | ||
2602 | args.prod = ap->ip->i_d.di_extsize; | 2675 | args.prod = ap->ip->i_d.di_extsize; |
2603 | if ((args.mod = (xfs_extlen_t)do_mod(ap->off, args.prod))) | 2676 | if ((args.mod = (xfs_extlen_t)do_mod(ap->off, args.prod))) |
2604 | args.mod = (xfs_extlen_t)(args.prod - args.mod); | 2677 | args.mod = (xfs_extlen_t)(args.prod - args.mod); |
2605 | } else if (mp->m_sb.sb_blocksize >= NBPP) { | 2678 | } else if (unlikely(mp->m_sb.sb_blocksize >= NBPP)) { |
2606 | args.prod = 1; | 2679 | args.prod = 1; |
2607 | args.mod = 0; | 2680 | args.mod = 0; |
2608 | } else { | 2681 | } else { |
@@ -3580,14 +3653,16 @@ xfs_bmap_search_extents( | |||
3580 | 3653 | ||
3581 | ep = xfs_bmap_do_search_extents(base, lastx, nextents, bno, eofp, | 3654 | ep = xfs_bmap_do_search_extents(base, lastx, nextents, bno, eofp, |
3582 | lastxp, gotp, prevp); | 3655 | lastxp, gotp, prevp); |
3583 | rt = ip->i_d.di_flags & XFS_DIFLAG_REALTIME; | 3656 | rt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip); |
3584 | if(!rt && !gotp->br_startblock && (*lastxp != NULLEXTNUM)) { | 3657 | if (unlikely(!rt && !gotp->br_startblock && (*lastxp != NULLEXTNUM))) { |
3585 | cmn_err(CE_PANIC,"Access to block zero: fs: <%s> inode: %lld " | 3658 | cmn_err(CE_PANIC,"Access to block zero: fs: <%s> inode: %lld " |
3586 | "start_block : %llx start_off : %llx blkcnt : %llx " | 3659 | "start_block : %llx start_off : %llx blkcnt : %llx " |
3587 | "extent-state : %x \n", | 3660 | "extent-state : %x \n", |
3588 | (ip->i_mount)->m_fsname,(long long)ip->i_ino, | 3661 | (ip->i_mount)->m_fsname, (long long)ip->i_ino, |
3589 | gotp->br_startblock, gotp->br_startoff, | 3662 | (unsigned long long)gotp->br_startblock, |
3590 | gotp->br_blockcount,gotp->br_state); | 3663 | (unsigned long long)gotp->br_startoff, |
3664 | (unsigned long long)gotp->br_blockcount, | ||
3665 | gotp->br_state); | ||
3591 | } | 3666 | } |
3592 | return ep; | 3667 | return ep; |
3593 | } | 3668 | } |
@@ -3875,7 +3950,7 @@ xfs_bmap_add_attrfork( | |||
3875 | ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size); | 3950 | ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size); |
3876 | if (!ip->i_d.di_forkoff) | 3951 | if (!ip->i_d.di_forkoff) |
3877 | ip->i_d.di_forkoff = mp->m_attroffset >> 3; | 3952 | ip->i_d.di_forkoff = mp->m_attroffset >> 3; |
3878 | else if (!(mp->m_flags & XFS_MOUNT_COMPAT_ATTR)) | 3953 | else if (mp->m_flags & XFS_MOUNT_ATTR2) |
3879 | version = 2; | 3954 | version = 2; |
3880 | break; | 3955 | break; |
3881 | default: | 3956 | default: |
@@ -4023,13 +4098,13 @@ xfs_bmap_compute_maxlevels( | |||
4023 | */ | 4098 | */ |
4024 | if (whichfork == XFS_DATA_FORK) { | 4099 | if (whichfork == XFS_DATA_FORK) { |
4025 | maxleafents = MAXEXTNUM; | 4100 | maxleafents = MAXEXTNUM; |
4026 | sz = (mp->m_flags & XFS_MOUNT_COMPAT_ATTR) ? | 4101 | sz = (mp->m_flags & XFS_MOUNT_ATTR2) ? |
4027 | mp->m_attroffset : XFS_BMDR_SPACE_CALC(MINDBTPTRS); | 4102 | XFS_BMDR_SPACE_CALC(MINDBTPTRS) : mp->m_attroffset; |
4028 | } else { | 4103 | } else { |
4029 | maxleafents = MAXAEXTNUM; | 4104 | maxleafents = MAXAEXTNUM; |
4030 | sz = (mp->m_flags & XFS_MOUNT_COMPAT_ATTR) ? | 4105 | sz = (mp->m_flags & XFS_MOUNT_ATTR2) ? |
4031 | mp->m_sb.sb_inodesize - mp->m_attroffset : | 4106 | XFS_BMDR_SPACE_CALC(MINABTPTRS) : |
4032 | XFS_BMDR_SPACE_CALC(MINABTPTRS); | 4107 | mp->m_sb.sb_inodesize - mp->m_attroffset; |
4033 | } | 4108 | } |
4034 | maxrootrecs = (int)XFS_BTREE_BLOCK_MAXRECS(sz, xfs_bmdr, 0); | 4109 | maxrootrecs = (int)XFS_BTREE_BLOCK_MAXRECS(sz, xfs_bmdr, 0); |
4035 | minleafrecs = mp->m_bmap_dmnr[0]; | 4110 | minleafrecs = mp->m_bmap_dmnr[0]; |
@@ -4418,8 +4493,8 @@ xfs_bmap_read_extents( | |||
4418 | num_recs = be16_to_cpu(block->bb_numrecs); | 4493 | num_recs = be16_to_cpu(block->bb_numrecs); |
4419 | if (unlikely(i + num_recs > room)) { | 4494 | if (unlikely(i + num_recs > room)) { |
4420 | ASSERT(i + num_recs <= room); | 4495 | ASSERT(i + num_recs <= room); |
4421 | xfs_fs_cmn_err(CE_WARN, ip->i_mount, | 4496 | xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount, |
4422 | "corrupt dinode %Lu, (btree extents). Unmount and run xfs_repair.", | 4497 | "corrupt dinode %Lu, (btree extents).", |
4423 | (unsigned long long) ip->i_ino); | 4498 | (unsigned long long) ip->i_ino); |
4424 | XFS_ERROR_REPORT("xfs_bmap_read_extents(1)", | 4499 | XFS_ERROR_REPORT("xfs_bmap_read_extents(1)", |
4425 | XFS_ERRLEVEL_LOW, | 4500 | XFS_ERRLEVEL_LOW, |
@@ -4590,6 +4665,7 @@ xfs_bmapi( | |||
4590 | char contig; /* allocation must be one extent */ | 4665 | char contig; /* allocation must be one extent */ |
4591 | char delay; /* this request is for delayed alloc */ | 4666 | char delay; /* this request is for delayed alloc */ |
4592 | char exact; /* don't do all of wasdelayed extent */ | 4667 | char exact; /* don't do all of wasdelayed extent */ |
4668 | char convert; /* unwritten extent I/O completion */ | ||
4593 | xfs_bmbt_rec_t *ep; /* extent list entry pointer */ | 4669 | xfs_bmbt_rec_t *ep; /* extent list entry pointer */ |
4594 | int error; /* error return */ | 4670 | int error; /* error return */ |
4595 | xfs_bmbt_irec_t got; /* current extent list record */ | 4671 | xfs_bmbt_irec_t got; /* current extent list record */ |
@@ -4643,7 +4719,7 @@ xfs_bmapi( | |||
4643 | } | 4719 | } |
4644 | if (XFS_FORCED_SHUTDOWN(mp)) | 4720 | if (XFS_FORCED_SHUTDOWN(mp)) |
4645 | return XFS_ERROR(EIO); | 4721 | return XFS_ERROR(EIO); |
4646 | rt = XFS_IS_REALTIME_INODE(ip); | 4722 | rt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip); |
4647 | ifp = XFS_IFORK_PTR(ip, whichfork); | 4723 | ifp = XFS_IFORK_PTR(ip, whichfork); |
4648 | ASSERT(ifp->if_ext_max == | 4724 | ASSERT(ifp->if_ext_max == |
4649 | XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); | 4725 | XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); |
@@ -4654,6 +4730,7 @@ xfs_bmapi( | |||
4654 | delay = (flags & XFS_BMAPI_DELAY) != 0; | 4730 | delay = (flags & XFS_BMAPI_DELAY) != 0; |
4655 | trim = (flags & XFS_BMAPI_ENTIRE) == 0; | 4731 | trim = (flags & XFS_BMAPI_ENTIRE) == 0; |
4656 | userdata = (flags & XFS_BMAPI_METADATA) == 0; | 4732 | userdata = (flags & XFS_BMAPI_METADATA) == 0; |
4733 | convert = (flags & XFS_BMAPI_CONVERT) != 0; | ||
4657 | exact = (flags & XFS_BMAPI_EXACT) != 0; | 4734 | exact = (flags & XFS_BMAPI_EXACT) != 0; |
4658 | rsvd = (flags & XFS_BMAPI_RSVBLOCKS) != 0; | 4735 | rsvd = (flags & XFS_BMAPI_RSVBLOCKS) != 0; |
4659 | contig = (flags & XFS_BMAPI_CONTIG) != 0; | 4736 | contig = (flags & XFS_BMAPI_CONTIG) != 0; |
@@ -4748,15 +4825,25 @@ xfs_bmapi( | |||
4748 | } | 4825 | } |
4749 | minlen = contig ? alen : 1; | 4826 | minlen = contig ? alen : 1; |
4750 | if (delay) { | 4827 | if (delay) { |
4751 | xfs_extlen_t extsz = 0; | 4828 | xfs_extlen_t extsz; |
4752 | 4829 | ||
4753 | /* Figure out the extent size, adjust alen */ | 4830 | /* Figure out the extent size, adjust alen */ |
4754 | if (rt) { | 4831 | if (rt) { |
4755 | if (!(extsz = ip->i_d.di_extsize)) | 4832 | if (!(extsz = ip->i_d.di_extsize)) |
4756 | extsz = mp->m_sb.sb_rextsize; | 4833 | extsz = mp->m_sb.sb_rextsize; |
4757 | alen = roundup(alen, extsz); | 4834 | } else { |
4758 | extsz = alen / mp->m_sb.sb_rextsize; | 4835 | extsz = ip->i_d.di_extsize; |
4759 | } | 4836 | } |
4837 | if (extsz) { | ||
4838 | error = xfs_bmap_extsize_align(mp, | ||
4839 | &got, &prev, extsz, | ||
4840 | rt, eof, delay, convert, | ||
4841 | &aoff, &alen); | ||
4842 | ASSERT(!error); | ||
4843 | } | ||
4844 | |||
4845 | if (rt) | ||
4846 | extsz = alen / mp->m_sb.sb_rextsize; | ||
4760 | 4847 | ||
4761 | /* | 4848 | /* |
4762 | * Make a transaction-less quota reservation for | 4849 | * Make a transaction-less quota reservation for |
@@ -4785,32 +4872,33 @@ xfs_bmapi( | |||
4785 | xfs_bmap_worst_indlen(ip, alen); | 4872 | xfs_bmap_worst_indlen(ip, alen); |
4786 | ASSERT(indlen > 0); | 4873 | ASSERT(indlen > 0); |
4787 | 4874 | ||
4788 | if (rt) | 4875 | if (rt) { |
4789 | error = xfs_mod_incore_sb(mp, | 4876 | error = xfs_mod_incore_sb(mp, |
4790 | XFS_SBS_FREXTENTS, | 4877 | XFS_SBS_FREXTENTS, |
4791 | -(extsz), rsvd); | 4878 | -(extsz), rsvd); |
4792 | else | 4879 | } else { |
4793 | error = xfs_mod_incore_sb(mp, | 4880 | error = xfs_mod_incore_sb(mp, |
4794 | XFS_SBS_FDBLOCKS, | 4881 | XFS_SBS_FDBLOCKS, |
4795 | -(alen), rsvd); | 4882 | -(alen), rsvd); |
4883 | } | ||
4796 | if (!error) { | 4884 | if (!error) { |
4797 | error = xfs_mod_incore_sb(mp, | 4885 | error = xfs_mod_incore_sb(mp, |
4798 | XFS_SBS_FDBLOCKS, | 4886 | XFS_SBS_FDBLOCKS, |
4799 | -(indlen), rsvd); | 4887 | -(indlen), rsvd); |
4800 | if (error && rt) { | 4888 | if (error && rt) |
4801 | xfs_mod_incore_sb(ip->i_mount, | 4889 | xfs_mod_incore_sb(mp, |
4802 | XFS_SBS_FREXTENTS, | 4890 | XFS_SBS_FREXTENTS, |
4803 | extsz, rsvd); | 4891 | extsz, rsvd); |
4804 | } else if (error) { | 4892 | else if (error) |
4805 | xfs_mod_incore_sb(ip->i_mount, | 4893 | xfs_mod_incore_sb(mp, |
4806 | XFS_SBS_FDBLOCKS, | 4894 | XFS_SBS_FDBLOCKS, |
4807 | alen, rsvd); | 4895 | alen, rsvd); |
4808 | } | ||
4809 | } | 4896 | } |
4810 | 4897 | ||
4811 | if (error) { | 4898 | if (error) { |
4812 | if (XFS_IS_QUOTA_ON(ip->i_mount)) | 4899 | if (XFS_IS_QUOTA_ON(mp)) |
4813 | /* unreserve the blocks now */ | 4900 | /* unreserve the blocks now */ |
4901 | (void) | ||
4814 | XFS_TRANS_UNRESERVE_QUOTA_NBLKS( | 4902 | XFS_TRANS_UNRESERVE_QUOTA_NBLKS( |
4815 | mp, NULL, ip, | 4903 | mp, NULL, ip, |
4816 | (long)alen, 0, rt ? | 4904 | (long)alen, 0, rt ? |
@@ -4849,6 +4937,7 @@ xfs_bmapi( | |||
4849 | bma.firstblock = *firstblock; | 4937 | bma.firstblock = *firstblock; |
4850 | bma.alen = alen; | 4938 | bma.alen = alen; |
4851 | bma.off = aoff; | 4939 | bma.off = aoff; |
4940 | bma.conv = convert; | ||
4852 | bma.wasdel = wasdelay; | 4941 | bma.wasdel = wasdelay; |
4853 | bma.minlen = minlen; | 4942 | bma.minlen = minlen; |
4854 | bma.low = flist->xbf_low; | 4943 | bma.low = flist->xbf_low; |
@@ -5270,8 +5359,7 @@ xfs_bunmapi( | |||
5270 | return 0; | 5359 | return 0; |
5271 | } | 5360 | } |
5272 | XFS_STATS_INC(xs_blk_unmap); | 5361 | XFS_STATS_INC(xs_blk_unmap); |
5273 | isrt = (whichfork == XFS_DATA_FORK) && | 5362 | isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip); |
5274 | (ip->i_d.di_flags & XFS_DIFLAG_REALTIME); | ||
5275 | start = bno; | 5363 | start = bno; |
5276 | bno = start + len - 1; | 5364 | bno = start + len - 1; |
5277 | ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, | 5365 | ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, |
@@ -5443,7 +5531,7 @@ xfs_bunmapi( | |||
5443 | } | 5531 | } |
5444 | if (wasdel) { | 5532 | if (wasdel) { |
5445 | ASSERT(STARTBLOCKVAL(del.br_startblock) > 0); | 5533 | ASSERT(STARTBLOCKVAL(del.br_startblock) > 0); |
5446 | /* Update realtim/data freespace, unreserve quota */ | 5534 | /* Update realtime/data freespace, unreserve quota */ |
5447 | if (isrt) { | 5535 | if (isrt) { |
5448 | xfs_filblks_t rtexts; | 5536 | xfs_filblks_t rtexts; |
5449 | 5537 | ||
@@ -5451,14 +5539,14 @@ xfs_bunmapi( | |||
5451 | do_div(rtexts, mp->m_sb.sb_rextsize); | 5539 | do_div(rtexts, mp->m_sb.sb_rextsize); |
5452 | xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS, | 5540 | xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS, |
5453 | (int)rtexts, rsvd); | 5541 | (int)rtexts, rsvd); |
5454 | XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, NULL, ip, | 5542 | (void)XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, |
5455 | -((long)del.br_blockcount), 0, | 5543 | NULL, ip, -((long)del.br_blockcount), 0, |
5456 | XFS_QMOPT_RES_RTBLKS); | 5544 | XFS_QMOPT_RES_RTBLKS); |
5457 | } else { | 5545 | } else { |
5458 | xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, | 5546 | xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, |
5459 | (int)del.br_blockcount, rsvd); | 5547 | (int)del.br_blockcount, rsvd); |
5460 | XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, NULL, ip, | 5548 | (void)XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, |
5461 | -((long)del.br_blockcount), 0, | 5549 | NULL, ip, -((long)del.br_blockcount), 0, |
5462 | XFS_QMOPT_RES_REGBLKS); | 5550 | XFS_QMOPT_RES_REGBLKS); |
5463 | } | 5551 | } |
5464 | ip->i_delayed_blks -= del.br_blockcount; | 5552 | ip->i_delayed_blks -= del.br_blockcount; |
@@ -5652,7 +5740,9 @@ xfs_getbmap( | |||
5652 | ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) | 5740 | ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) |
5653 | return XFS_ERROR(EINVAL); | 5741 | return XFS_ERROR(EINVAL); |
5654 | if (whichfork == XFS_DATA_FORK) { | 5742 | if (whichfork == XFS_DATA_FORK) { |
5655 | if (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC) { | 5743 | if ((ip->i_d.di_extsize && (ip->i_d.di_flags & |
5744 | (XFS_DIFLAG_REALTIME|XFS_DIFLAG_EXTSIZE))) || | ||
5745 | ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)){ | ||
5656 | prealloced = 1; | 5746 | prealloced = 1; |
5657 | fixlen = XFS_MAXIOFFSET(mp); | 5747 | fixlen = XFS_MAXIOFFSET(mp); |
5658 | } else { | 5748 | } else { |