···231231 return -EINVAL;232232233233 /* Return error if mode is not supported */234234- if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |235235- FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE))234234+ if (mode & ~FALLOC_FL_SUPPORTED_MASK)236235 return -EOPNOTSUPP;237236238237 /* Punch hole and zero range are mutually exclusive */···247248 /* Collapse range should only be used exclusively. */248249 if ((mode & FALLOC_FL_COLLAPSE_RANGE) &&249250 (mode & ~FALLOC_FL_COLLAPSE_RANGE))251251+ return -EINVAL;252252+253253+ /* Insert range should only be used exclusively. */254254+ if ((mode & FALLOC_FL_INSERT_RANGE) &&255255+ (mode & ~FALLOC_FL_INSERT_RANGE))250256 return -EINVAL;251257252258 if (!(file->f_mode & FMODE_WRITE))
+320-50
fs/xfs/libxfs/xfs_bmap.c
···54865486 int *current_ext,54875487 struct xfs_bmbt_rec_host *gotp,54885488 struct xfs_btree_cur *cur,54895489- int *logflags)54895489+ int *logflags,54905490+ enum shift_direction direction)54905491{54915492 struct xfs_ifork *ifp;54925493 struct xfs_mount *mp;54935494 xfs_fileoff_t startoff;54945494- struct xfs_bmbt_rec_host *leftp;54955495+ struct xfs_bmbt_rec_host *adj_irecp;54955496 struct xfs_bmbt_irec got;54965496- struct xfs_bmbt_irec left;54975497+ struct xfs_bmbt_irec adj_irec;54975498 int error;54985499 int i;55005500+ int total_extents;5499550155005502 mp = ip->i_mount;55015503 ifp = XFS_IFORK_PTR(ip, whichfork);55045504+ total_extents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t);5502550555035506 xfs_bmbt_get_all(gotp, &got);55045504- startoff = got.br_startoff - offset_shift_fsb;5505550755065508 /* delalloc extents should be prevented by caller */55075509 XFS_WANT_CORRUPTED_RETURN(mp, !isnullstartblock(got.br_startblock));5508551055095509- /*55105510- * Check for merge if we've got an extent to the left, otherwise make55115511- * sure there's enough room at the start of the file for the shift.55125512- */55135513- if (*current_ext) {55145514- /* grab the left extent and check for a large enough hole */55155515- leftp = xfs_iext_get_ext(ifp, *current_ext - 1);55165516- xfs_bmbt_get_all(leftp, &left);55115511+ if (direction == SHIFT_LEFT) {55125512+ startoff = got.br_startoff - offset_shift_fsb;5517551355185518- if (startoff < left.br_startoff + left.br_blockcount)55145514+ /*55155515+ * Check for merge if we've got an extent to the left,55165516+ * otherwise make sure there's enough room at the start55175517+ * of the file for the shift.55185518+ */55195519+ if (!*current_ext) {55205520+ if (got.br_startoff < offset_shift_fsb)55215521+ return -EINVAL;55225522+ goto update_current_ext;55235523+ }55245524+ /*55255525+ * grab the left extent and check for a large55265526+ * enough hole.55275527+ */55285528+ adj_irecp = xfs_iext_get_ext(ifp, *current_ext - 1);55295529+ xfs_bmbt_get_all(adj_irecp, &adj_irec);55305530+55315531+ if (startoff <55325532+ adj_irec.br_startoff + adj_irec.br_blockcount)55195533 return -EINVAL;5520553455215535 /* check whether to merge the extent or shift it down */55225522- if (xfs_bmse_can_merge(&left, &got, offset_shift_fsb)) {55365536+ if (xfs_bmse_can_merge(&adj_irec, &got,55375537+ offset_shift_fsb)) {55235538 return xfs_bmse_merge(ip, whichfork, offset_shift_fsb,55245524- *current_ext, gotp, leftp, cur,55255525- logflags);55395539+ *current_ext, gotp, adj_irecp,55405540+ cur, logflags);55265541 }55275527- } else if (got.br_startoff < offset_shift_fsb)55285528- return -EINVAL;55295529-55425542+ } else {55435543+ startoff = got.br_startoff + offset_shift_fsb;55445544+ /* nothing to move if this is the last extent */55455545+ if (*current_ext >= (total_extents - 1))55465546+ goto update_current_ext;55475547+ /*55485548+ * If this is not the last extent in the file, make sure there55495549+ * is enough room between current extent and next extent for55505550+ * accommodating the shift.55515551+ */55525552+ adj_irecp = xfs_iext_get_ext(ifp, *current_ext + 1);55535553+ xfs_bmbt_get_all(adj_irecp, &adj_irec);55545554+ if (startoff + got.br_blockcount > adj_irec.br_startoff)55555555+ return -EINVAL;55565556+ /*55575557+ * Unlike a left shift (which involves a hole punch),55585558+ * a right shift does not modify extent neighbors55595559+ * in any way. We should never find mergeable extents55605560+ * in this scenario. Check anyways and warn if we55615561+ * encounter two extents that could be one.55625562+ */55635563+ if (xfs_bmse_can_merge(&got, &adj_irec, offset_shift_fsb))55645564+ WARN_ON_ONCE(1);55655565+ }55305566 /*55315567 * Increment the extent index for the next iteration, update the start55325568 * offset of the in-core extent and update the btree if applicable.55335569 */55345534- (*current_ext)++;55705570+update_current_ext:55715571+ if (direction == SHIFT_LEFT)55725572+ (*current_ext)++;55735573+ else55745574+ (*current_ext)--;55355575 xfs_bmbt_set_startoff(gotp, startoff);55365576 *logflags |= XFS_ILOG_CORE;55375577 if (!cur) {···5587554755885548 got.br_startoff = startoff;55895549 return xfs_bmbt_update(cur, got.br_startoff, got.br_startblock,55905590- got.br_blockcount, got.br_state);55505550+ got.br_blockcount, got.br_state);55915551}5592555255935553/*55945594- * Shift extent records to the left to cover a hole.55545554+ * Shift extent records to the left/right to cover/create a hole.55955555 *55965556 * The maximum number of extents to be shifted in a single operation is55975597- * @num_exts. @start_fsb specifies the file offset to start the shift and the55575557+ * @num_exts. @stop_fsb specifies the file offset at which to stop shift and the55985558 * file offset where we've left off is returned in @next_fsb. @offset_shift_fsb55995559 * is the length by which each extent is shifted. If there is no hole to shift56005560 * the extents into, this will be considered invalid operation and we abort···56045564xfs_bmap_shift_extents(56055565 struct xfs_trans *tp,56065566 struct xfs_inode *ip,56075607- xfs_fileoff_t start_fsb,55675567+ xfs_fileoff_t *next_fsb,56085568 xfs_fileoff_t offset_shift_fsb,56095569 int *done,56105610- xfs_fileoff_t *next_fsb,55705570+ xfs_fileoff_t stop_fsb,56115571 xfs_fsblock_t *firstblock,56125572 struct xfs_bmap_free *flist,55735573+ enum shift_direction direction,56135574 int num_exts)56145575{56155576 struct xfs_btree_cur *cur = NULL;···56205579 struct xfs_ifork *ifp;56215580 xfs_extnum_t nexts = 0;56225581 xfs_extnum_t current_ext;55825582+ xfs_extnum_t total_extents;55835583+ xfs_extnum_t stop_extent;56235584 int error = 0;56245585 int whichfork = XFS_DATA_FORK;56255586 int logflags = 0;56265626- int total_extents;5627558756285588 if (unlikely(XFS_TEST_ERROR(56295589 (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&···5640559856415599 ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));56425600 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));56015601+ ASSERT(direction == SHIFT_LEFT || direction == SHIFT_RIGHT);56025602+ ASSERT(*next_fsb != NULLFSBLOCK || direction == SHIFT_RIGHT);5643560356445604 ifp = XFS_IFORK_PTR(ip, whichfork);56455605 if (!(ifp->if_flags & XFS_IFEXTENTS)) {···56595615 }5660561656615617 /*56625662- * Look up the extent index for the fsb where we start shifting. We can56635663- * henceforth iterate with current_ext as extent list changes are locked56645664- * out via ilock.56655665- *56665666- * gotp can be null in 2 cases: 1) if there are no extents or 2)56675667- * start_fsb lies in a hole beyond which there are no extents. Either56685668- * way, we are done.56695669- */56705670- gotp = xfs_iext_bno_to_ext(ifp, start_fsb, ¤t_ext);56715671- if (!gotp) {56725672- *done = 1;56735673- goto del_cursor;56745674- }56755675-56765676- /*56775618 * There may be delalloc extents in the data fork before the range we56785619 * are collapsing out, so we cannot use the count of real extents here.56795620 * Instead we have to calculate it from the incore fork.56805621 */56815622 total_extents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t);56825682- while (nexts++ < num_exts && current_ext < total_extents) {56235623+ if (total_extents == 0) {56245624+ *done = 1;56255625+ goto del_cursor;56265626+ }56275627+56285628+ /*56295629+ * In case of first right shift, we need to initialize next_fsb56305630+ */56315631+ if (*next_fsb == NULLFSBLOCK) {56325632+ gotp = xfs_iext_get_ext(ifp, total_extents - 1);56335633+ xfs_bmbt_get_all(gotp, &got);56345634+ *next_fsb = got.br_startoff;56355635+ if (stop_fsb > *next_fsb) {56365636+ *done = 1;56375637+ goto del_cursor;56385638+ }56395639+ }56405640+56415641+ /* Lookup the extent index at which we have to stop */56425642+ if (direction == SHIFT_RIGHT) {56435643+ gotp = xfs_iext_bno_to_ext(ifp, stop_fsb, &stop_extent);56445644+ /* Make stop_extent exclusive of shift range */56455645+ stop_extent--;56465646+ } else56475647+ stop_extent = total_extents;56485648+56495649+ /*56505650+ * Look up the extent index for the fsb where we start shifting. We can56515651+ * henceforth iterate with current_ext as extent list changes are locked56525652+ * out via ilock.56535653+ *56545654+ * gotp can be null in 2 cases: 1) if there are no extents or 2)56555655+ * *next_fsb lies in a hole beyond which there are no extents. Either56565656+ * way, we are done.56575657+ */56585658+ gotp = xfs_iext_bno_to_ext(ifp, *next_fsb, ¤t_ext);56595659+ if (!gotp) {56605660+ *done = 1;56615661+ goto del_cursor;56625662+ }56635663+56645664+ /* some sanity checking before we finally start shifting extents */56655665+ if ((direction == SHIFT_LEFT && current_ext >= stop_extent) ||56665666+ (direction == SHIFT_RIGHT && current_ext <= stop_extent)) {56675667+ error = -EIO;56685668+ goto del_cursor;56695669+ }56705670+56715671+ while (nexts++ < num_exts) {56835672 error = xfs_bmse_shift_one(ip, whichfork, offset_shift_fsb,56845684- ¤t_ext, gotp, cur, &logflags);56735673+ ¤t_ext, gotp, cur, &logflags,56745674+ direction);56855675 if (error)56865676 goto del_cursor;56775677+ /*56785678+ * If there was an extent merge during the shift, the extent56795679+ * count can change. Update the total and grade the next record.56805680+ */56815681+ if (direction == SHIFT_LEFT) {56825682+ total_extents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t);56835683+ stop_extent = total_extents;56845684+ }5687568556885688- /* update total extent count and grab the next record */56895689- total_extents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t);56905690- if (current_ext >= total_extents)56865686+ if (current_ext == stop_extent) {56875687+ *done = 1;56885688+ *next_fsb = NULLFSBLOCK;56915689 break;56905690+ }56925691 gotp = xfs_iext_get_ext(ifp, current_ext);56935692 }5694569356955695- /* Check if we are done */56965696- if (current_ext == total_extents) {56975697- *done = 1;56985698- } else if (next_fsb) {56945694+ if (!*done) {56995695 xfs_bmbt_get_all(gotp, &got);57005696 *next_fsb = got.br_startoff;57015697 }···57485664 if (logflags)57495665 xfs_trans_log_inode(tp, ip, logflags);5750566656675667+ return error;56685668+}56695669+56705670+/*56715671+ * Splits an extent into two extents at split_fsb block such that it is56725672+ * the first block of the current_ext. @current_ext is a target extent56735673+ * to be split. @split_fsb is a block where the extents is split.56745674+ * If split_fsb lies in a hole or the first block of extents, just return 0.56755675+ */56765676+STATIC int56775677+xfs_bmap_split_extent_at(56785678+ struct xfs_trans *tp,56795679+ struct xfs_inode *ip,56805680+ xfs_fileoff_t split_fsb,56815681+ xfs_fsblock_t *firstfsb,56825682+ struct xfs_bmap_free *free_list)56835683+{56845684+ int whichfork = XFS_DATA_FORK;56855685+ struct xfs_btree_cur *cur = NULL;56865686+ struct xfs_bmbt_rec_host *gotp;56875687+ struct xfs_bmbt_irec got;56885688+ struct xfs_bmbt_irec new; /* split extent */56895689+ struct xfs_mount *mp = ip->i_mount;56905690+ struct xfs_ifork *ifp;56915691+ xfs_fsblock_t gotblkcnt; /* new block count for got */56925692+ xfs_extnum_t current_ext;56935693+ int error = 0;56945694+ int logflags = 0;56955695+ int i = 0;56965696+56975697+ if (unlikely(XFS_TEST_ERROR(56985698+ (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&56995699+ XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),57005700+ mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) {57015701+ XFS_ERROR_REPORT("xfs_bmap_split_extent_at",57025702+ XFS_ERRLEVEL_LOW, mp);57035703+ return -EFSCORRUPTED;57045704+ }57055705+57065706+ if (XFS_FORCED_SHUTDOWN(mp))57075707+ return -EIO;57085708+57095709+ ifp = XFS_IFORK_PTR(ip, whichfork);57105710+ if (!(ifp->if_flags & XFS_IFEXTENTS)) {57115711+ /* Read in all the extents */57125712+ error = xfs_iread_extents(tp, ip, whichfork);57135713+ if (error)57145714+ return error;57155715+ }57165716+57175717+ /*57185718+ * gotp can be null in 2 cases: 1) if there are no extents57195719+ * or 2) split_fsb lies in a hole beyond which there are57205720+ * no extents. Either way, we are done.57215721+ */57225722+ gotp = xfs_iext_bno_to_ext(ifp, split_fsb, ¤t_ext);57235723+ if (!gotp)57245724+ return 0;57255725+57265726+ xfs_bmbt_get_all(gotp, &got);57275727+57285728+ /*57295729+ * Check split_fsb lies in a hole or the start boundary offset57305730+ * of the extent.57315731+ */57325732+ if (got.br_startoff >= split_fsb)57335733+ return 0;57345734+57355735+ gotblkcnt = split_fsb - got.br_startoff;57365736+ new.br_startoff = split_fsb;57375737+ new.br_startblock = got.br_startblock + gotblkcnt;57385738+ new.br_blockcount = got.br_blockcount - gotblkcnt;57395739+ new.br_state = got.br_state;57405740+57415741+ if (ifp->if_flags & XFS_IFBROOT) {57425742+ cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);57435743+ cur->bc_private.b.firstblock = *firstfsb;57445744+ cur->bc_private.b.flist = free_list;57455745+ cur->bc_private.b.flags = 0;57465746+ error = xfs_bmbt_lookup_eq(cur, got.br_startoff,57475747+ got.br_startblock,57485748+ got.br_blockcount,57495749+ &i);57505750+ if (error)57515751+ goto del_cursor;57525752+ XFS_WANT_CORRUPTED_GOTO(mp, i == 1, del_cursor);57535753+ }57545754+57555755+ xfs_bmbt_set_blockcount(gotp, gotblkcnt);57565756+ got.br_blockcount = gotblkcnt;57575757+57585758+ logflags = XFS_ILOG_CORE;57595759+ if (cur) {57605760+ error = xfs_bmbt_update(cur, got.br_startoff,57615761+ got.br_startblock,57625762+ got.br_blockcount,57635763+ got.br_state);57645764+ if (error)57655765+ goto del_cursor;57665766+ } else57675767+ logflags |= XFS_ILOG_DEXT;57685768+57695769+ /* Add new extent */57705770+ current_ext++;57715771+ xfs_iext_insert(ip, current_ext, 1, &new, 0);57725772+ XFS_IFORK_NEXT_SET(ip, whichfork,57735773+ XFS_IFORK_NEXTENTS(ip, whichfork) + 1);57745774+57755775+ if (cur) {57765776+ error = xfs_bmbt_lookup_eq(cur, new.br_startoff,57775777+ new.br_startblock, new.br_blockcount,57785778+ &i);57795779+ if (error)57805780+ goto del_cursor;57815781+ XFS_WANT_CORRUPTED_GOTO(mp, i == 0, del_cursor);57825782+ cur->bc_rec.b.br_state = new.br_state;57835783+57845784+ error = xfs_btree_insert(cur, &i);57855785+ if (error)57865786+ goto del_cursor;57875787+ XFS_WANT_CORRUPTED_GOTO(mp, i == 1, del_cursor);57885788+ }57895789+57905790+ /*57915791+ * Convert to a btree if necessary.57925792+ */57935793+ if (xfs_bmap_needs_btree(ip, whichfork)) {57945794+ int tmp_logflags; /* partial log flag return val */57955795+57965796+ ASSERT(cur == NULL);57975797+ error = xfs_bmap_extents_to_btree(tp, ip, firstfsb, free_list,57985798+ &cur, 0, &tmp_logflags, whichfork);57995799+ logflags |= tmp_logflags;58005800+ }58015801+58025802+del_cursor:58035803+ if (cur) {58045804+ cur->bc_private.b.allocated = 0;58055805+ xfs_btree_del_cursor(cur,58065806+ error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);58075807+ }58085808+58095809+ if (logflags)58105810+ xfs_trans_log_inode(tp, ip, logflags);58115811+ return error;58125812+}58135813+58145814+int58155815+xfs_bmap_split_extent(58165816+ struct xfs_inode *ip,58175817+ xfs_fileoff_t split_fsb)58185818+{58195819+ struct xfs_mount *mp = ip->i_mount;58205820+ struct xfs_trans *tp;58215821+ struct xfs_bmap_free free_list;58225822+ xfs_fsblock_t firstfsb;58235823+ int committed;58245824+ int error;58255825+58265826+ tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);58275827+ error = xfs_trans_reserve(tp, &M_RES(mp)->tr_write,58285828+ XFS_DIOSTRAT_SPACE_RES(mp, 0), 0);58295829+ if (error) {58305830+ xfs_trans_cancel(tp, 0);58315831+ return error;58325832+ }58335833+58345834+ xfs_ilock(ip, XFS_ILOCK_EXCL);58355835+ xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);58365836+58375837+ xfs_bmap_init(&free_list, &firstfsb);58385838+58395839+ error = xfs_bmap_split_extent_at(tp, ip, split_fsb,58405840+ &firstfsb, &free_list);58415841+ if (error)58425842+ goto out;58435843+58445844+ error = xfs_bmap_finish(&tp, &free_list, &committed);58455845+ if (error)58465846+ goto out;58475847+58485848+ return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);58495849+58505850+58515851+out:58525852+ xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);57515853 return error;57525854}
···13761376}1377137713781378/*13791379- * xfs_collapse_file_space()13801380- * This routine frees disk space and shift extent for the given file.13811381- * The first thing we do is to free data blocks in the specified range13821382- * by calling xfs_free_file_space(). It would also sync dirty data13831383- * and invalidate page cache over the region on which collapse range13841384- * is working. And Shift extent records to the left to cover a hole.13851385- * RETURNS:13861386- * 0 on success13871387- * errno on error13881388- *13791379+ * @next_fsb will keep track of the extent currently undergoing shift.13801380+ * @stop_fsb will keep track of the extent at which we have to stop.13811381+ * If we are shifting left, we will start with block (offset + len) and13821382+ * shift each extent till last extent.13831383+ * If we are shifting right, we will start with last extent inside file space13841384+ * and continue until we reach the block corresponding to offset.13891385 */13901386int13911391-xfs_collapse_file_space(13921392- struct xfs_inode *ip,13931393- xfs_off_t offset,13941394- xfs_off_t len)13871387+xfs_shift_file_space(13881388+ struct xfs_inode *ip,13891389+ xfs_off_t offset,13901390+ xfs_off_t len,13911391+ enum shift_direction direction)13951392{13961393 int done = 0;13971394 struct xfs_mount *mp = ip->i_mount;···13971400 struct xfs_bmap_free free_list;13981401 xfs_fsblock_t first_block;13991402 int committed;14001400- xfs_fileoff_t start_fsb;14031403+ xfs_fileoff_t stop_fsb;14011404 xfs_fileoff_t next_fsb;14021405 xfs_fileoff_t shift_fsb;1403140614041404- ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));14071407+ ASSERT(direction == SHIFT_LEFT || direction == SHIFT_RIGHT);1405140814061406- trace_xfs_collapse_file_space(ip);14091409+ if (direction == SHIFT_LEFT) {14101410+ next_fsb = XFS_B_TO_FSB(mp, offset + len);14111411+ stop_fsb = XFS_B_TO_FSB(mp, VFS_I(ip)->i_size);14121412+ } else {14131413+ /*14141414+ * If right shift, delegate the work of initialization of14151415+ * next_fsb to xfs_bmap_shift_extent as it has ilock held.14161416+ */14171417+ next_fsb = NULLFSBLOCK;14181418+ stop_fsb = XFS_B_TO_FSB(mp, offset);14191419+ }1407142014081408- next_fsb = XFS_B_TO_FSB(mp, offset + len);14091421 shift_fsb = XFS_B_TO_FSB(mp, len);14101410-14111411- error = xfs_free_file_space(ip, offset, len);14121412- if (error)14131413- return error;1414142214151423 /*14161424 * Trim eofblocks to avoid shifting uninitialized post-eof preallocation···1429142714301428 /*14311429 * Writeback and invalidate cache for the remainder of the file as we're14321432- * about to shift down every extent from the collapse range to EOF. The14331433- * free of the collapse range above might have already done some of14341434- * this, but we shouldn't rely on it to do anything outside of the range14351435- * that was freed.14301430+ * about to shift down every extent from offset to EOF.14361431 */14371432 error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping,14381438- offset + len, -1);14331433+ offset, -1);14391434 if (error)14401435 return error;14411436 error = invalidate_inode_pages2_range(VFS_I(ip)->i_mapping,14421442- (offset + len) >> PAGE_CACHE_SHIFT, -1);14371437+ offset >> PAGE_CACHE_SHIFT, -1);14431438 if (error)14441439 return error;14401440+14411441+ /*14421442+ * The extent shiting code works on extent granularity. So, if14431443+ * stop_fsb is not the starting block of extent, we need to split14441444+ * the extent at stop_fsb.14451445+ */14461446+ if (direction == SHIFT_RIGHT) {14471447+ error = xfs_bmap_split_extent(ip, stop_fsb);14481448+ if (error)14491449+ return error;14501450+ }1445145114461452 while (!error && !done) {14471453 tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);···14741464 if (error)14751465 goto out;1476146614771477- xfs_trans_ijoin(tp, ip, 0);14671467+ xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);1478146814791469 xfs_bmap_init(&free_list, &first_block);14801470···14821472 * We are using the write transaction in which max 2 bmbt14831473 * updates are allowed14841474 */14851485- start_fsb = next_fsb;14861486- error = xfs_bmap_shift_extents(tp, ip, start_fsb, shift_fsb,14871487- &done, &next_fsb, &first_block, &free_list,14881488- XFS_BMAP_MAX_SHIFT_EXTENTS);14751475+ error = xfs_bmap_shift_extents(tp, ip, &next_fsb, shift_fsb,14761476+ &done, stop_fsb, &first_block, &free_list,14771477+ direction, XFS_BMAP_MAX_SHIFT_EXTENTS);14891478 if (error)14901479 goto out;14911480···14931484 goto out;1494148514951486 error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);14961496- xfs_iunlock(ip, XFS_ILOCK_EXCL);14971487 }1498148814991489 return error;1500149015011491out:15021492 xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);15031503- xfs_iunlock(ip, XFS_ILOCK_EXCL);15041493 return error;14941494+}14951495+14961496+/*14971497+ * xfs_collapse_file_space()14981498+ * This routine frees disk space and shift extent for the given file.14991499+ * The first thing we do is to free data blocks in the specified range15001500+ * by calling xfs_free_file_space(). It would also sync dirty data15011501+ * and invalidate page cache over the region on which collapse range15021502+ * is working. And Shift extent records to the left to cover a hole.15031503+ * RETURNS:15041504+ * 0 on success15051505+ * errno on error15061506+ *15071507+ */15081508+int15091509+xfs_collapse_file_space(15101510+ struct xfs_inode *ip,15111511+ xfs_off_t offset,15121512+ xfs_off_t len)15131513+{15141514+ int error;15151515+15161516+ ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));15171517+ trace_xfs_collapse_file_space(ip);15181518+15191519+ error = xfs_free_file_space(ip, offset, len);15201520+ if (error)15211521+ return error;15221522+15231523+ return xfs_shift_file_space(ip, offset, len, SHIFT_LEFT);15241524+}15251525+15261526+/*15271527+ * xfs_insert_file_space()15281528+ * This routine create hole space by shifting extents for the given file.15291529+ * The first thing we do is to sync dirty data and invalidate page cache15301530+ * over the region on which insert range is working. And split an extent15311531+ * to two extents at given offset by calling xfs_bmap_split_extent.15321532+ * And shift all extent records which are laying between [offset,15331533+ * last allocated extent] to the right to reserve hole range.15341534+ * RETURNS:15351535+ * 0 on success15361536+ * errno on error15371537+ */15381538+int15391539+xfs_insert_file_space(15401540+ struct xfs_inode *ip,15411541+ loff_t offset,15421542+ loff_t len)15431543+{15441544+ ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));15451545+ trace_xfs_insert_file_space(ip);15461546+15471547+ return xfs_shift_file_space(ip, offset, len, SHIFT_RIGHT);15051548}1506154915071550/*
···4141 */4242#define FALLOC_FL_ZERO_RANGE 0x1043434444+/*4545+ * FALLOC_FL_INSERT_RANGE is use to insert space within the file size without4646+ * overwriting any existing data. The contents of the file beyond offset are4747+ * shifted towards right by len bytes to create a hole. As such, this4848+ * operation will increase the size of the file by len bytes.4949+ *5050+ * Different filesystems may implement different limitations on the granularity5151+ * of the operation. Most will limit operations to filesystem block size5252+ * boundaries, but this boundary may be larger or smaller depending on5353+ * the filesystem and/or the configuration of the filesystem or file.5454+ *5555+ * Attempting to insert space using this flag at OR beyond the end of5656+ * the file is considered an illegal operation - just use ftruncate(2) or5757+ * fallocate(2) with mode 0 for such type of operations.5858+ */5959+#define FALLOC_FL_INSERT_RANGE 0x206060+4461#endif /* _UAPI_FALLOC_H_ */