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 { |
