~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/xfs/xfs_dir2.c

Version: ~ [ linux-5.12-rc1 ] ~ [ linux-5.11.2 ] ~ [ linux-5.10.19 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.101 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.177 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.222 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.258 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.258 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
  3  * All Rights Reserved.
  4  *
  5  * This program is free software; you can redistribute it and/or
  6  * modify it under the terms of the GNU General Public License as
  7  * published by the Free Software Foundation.
  8  *
  9  * This program is distributed in the hope that it would be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12  * GNU General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU General Public License
 15  * along with this program; if not, write the Free Software Foundation,
 16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 17  */
 18 #include "xfs.h"
 19 #include "xfs_fs.h"
 20 #include "xfs_format.h"
 21 #include "xfs_log_format.h"
 22 #include "xfs_trans_resv.h"
 23 #include "xfs_inum.h"
 24 #include "xfs_sb.h"
 25 #include "xfs_ag.h"
 26 #include "xfs_mount.h"
 27 #include "xfs_da_format.h"
 28 #include "xfs_da_btree.h"
 29 #include "xfs_inode.h"
 30 #include "xfs_trans.h"
 31 #include "xfs_inode_item.h"
 32 #include "xfs_bmap.h"
 33 #include "xfs_dir2.h"
 34 #include "xfs_dir2_priv.h"
 35 #include "xfs_error.h"
 36 #include "xfs_trace.h"
 37 #include "xfs_dinode.h"
 38 
 39 struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR };
 40 
 41 
 42 /*
 43  * ASCII case-insensitive (ie. A-Z) support for directories that was
 44  * used in IRIX.
 45  */
 46 STATIC xfs_dahash_t
 47 xfs_ascii_ci_hashname(
 48         struct xfs_name *name)
 49 {
 50         xfs_dahash_t    hash;
 51         int             i;
 52 
 53         for (i = 0, hash = 0; i < name->len; i++)
 54                 hash = tolower(name->name[i]) ^ rol32(hash, 7);
 55 
 56         return hash;
 57 }
 58 
 59 STATIC enum xfs_dacmp
 60 xfs_ascii_ci_compname(
 61         struct xfs_da_args *args,
 62         const unsigned char *name,
 63         int             len)
 64 {
 65         enum xfs_dacmp  result;
 66         int             i;
 67 
 68         if (args->namelen != len)
 69                 return XFS_CMP_DIFFERENT;
 70 
 71         result = XFS_CMP_EXACT;
 72         for (i = 0; i < len; i++) {
 73                 if (args->name[i] == name[i])
 74                         continue;
 75                 if (tolower(args->name[i]) != tolower(name[i]))
 76                         return XFS_CMP_DIFFERENT;
 77                 result = XFS_CMP_CASE;
 78         }
 79 
 80         return result;
 81 }
 82 
 83 static struct xfs_nameops xfs_ascii_ci_nameops = {
 84         .hashname       = xfs_ascii_ci_hashname,
 85         .compname       = xfs_ascii_ci_compname,
 86 };
 87 
 88 void
 89 xfs_dir_mount(
 90         xfs_mount_t     *mp)
 91 {
 92         int     nodehdr_size;
 93 
 94 
 95         ASSERT(xfs_sb_version_hasdirv2(&mp->m_sb));
 96         ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <=
 97                XFS_MAX_BLOCKSIZE);
 98 
 99         mp->m_dir_inode_ops = xfs_dir_get_ops(mp, NULL);
100         mp->m_nondir_inode_ops = xfs_nondir_get_ops(mp, NULL);
101 
102         mp->m_dirblksize = 1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog);
103         mp->m_dirblkfsbs = 1 << mp->m_sb.sb_dirblklog;
104         mp->m_dirdatablk = xfs_dir2_db_to_da(mp, XFS_DIR2_DATA_FIRSTDB(mp));
105         mp->m_dirleafblk = xfs_dir2_db_to_da(mp, XFS_DIR2_LEAF_FIRSTDB(mp));
106         mp->m_dirfreeblk = xfs_dir2_db_to_da(mp, XFS_DIR2_FREE_FIRSTDB(mp));
107 
108         nodehdr_size = mp->m_dir_inode_ops->node_hdr_size;
109         mp->m_attr_node_ents = (mp->m_sb.sb_blocksize - nodehdr_size) /
110                                 (uint)sizeof(xfs_da_node_entry_t);
111         mp->m_dir_node_ents = (mp->m_dirblksize - nodehdr_size) /
112                                 (uint)sizeof(xfs_da_node_entry_t);
113 
114         mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100;
115         if (xfs_sb_version_hasasciici(&mp->m_sb))
116                 mp->m_dirnameops = &xfs_ascii_ci_nameops;
117         else
118                 mp->m_dirnameops = &xfs_default_nameops;
119 
120 }
121 
122 /*
123  * Return 1 if directory contains only "." and "..".
124  */
125 int
126 xfs_dir_isempty(
127         xfs_inode_t     *dp)
128 {
129         xfs_dir2_sf_hdr_t       *sfp;
130 
131         ASSERT(S_ISDIR(dp->i_d.di_mode));
132         if (dp->i_d.di_size == 0)       /* might happen during shutdown. */
133                 return 1;
134         if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp))
135                 return 0;
136         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
137         return !sfp->count;
138 }
139 
140 /*
141  * Validate a given inode number.
142  */
143 int
144 xfs_dir_ino_validate(
145         xfs_mount_t     *mp,
146         xfs_ino_t       ino)
147 {
148         xfs_agblock_t   agblkno;
149         xfs_agino_t     agino;
150         xfs_agnumber_t  agno;
151         int             ino_ok;
152         int             ioff;
153 
154         agno = XFS_INO_TO_AGNO(mp, ino);
155         agblkno = XFS_INO_TO_AGBNO(mp, ino);
156         ioff = XFS_INO_TO_OFFSET(mp, ino);
157         agino = XFS_OFFBNO_TO_AGINO(mp, agblkno, ioff);
158         ino_ok =
159                 agno < mp->m_sb.sb_agcount &&
160                 agblkno < mp->m_sb.sb_agblocks &&
161                 agblkno != 0 &&
162                 ioff < (1 << mp->m_sb.sb_inopblog) &&
163                 XFS_AGINO_TO_INO(mp, agno, agino) == ino;
164         if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE,
165                         XFS_RANDOM_DIR_INO_VALIDATE))) {
166                 xfs_warn(mp, "Invalid inode number 0x%Lx",
167                                 (unsigned long long) ino);
168                 XFS_ERROR_REPORT("xfs_dir_ino_validate", XFS_ERRLEVEL_LOW, mp);
169                 return XFS_ERROR(EFSCORRUPTED);
170         }
171         return 0;
172 }
173 
174 /*
175  * Initialize a directory with its "." and ".." entries.
176  */
177 int
178 xfs_dir_init(
179         xfs_trans_t     *tp,
180         xfs_inode_t     *dp,
181         xfs_inode_t     *pdp)
182 {
183         xfs_da_args_t   args;
184         int             error;
185 
186         memset((char *)&args, 0, sizeof(args));
187         args.dp = dp;
188         args.trans = tp;
189         ASSERT(S_ISDIR(dp->i_d.di_mode));
190         if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino)))
191                 return error;
192         return xfs_dir2_sf_create(&args, pdp->i_ino);
193 }
194 
195 /*
196   Enter a name in a directory.
197  */
198 int
199 xfs_dir_createname(
200         xfs_trans_t             *tp,
201         xfs_inode_t             *dp,
202         struct xfs_name         *name,
203         xfs_ino_t               inum,           /* new entry inode number */
204         xfs_fsblock_t           *first,         /* bmap's firstblock */
205         xfs_bmap_free_t         *flist,         /* bmap's freeblock list */
206         xfs_extlen_t            total)          /* bmap's total block count */
207 {
208         xfs_da_args_t           args;
209         int                     rval;
210         int                     v;              /* type-checking value */
211 
212         ASSERT(S_ISDIR(dp->i_d.di_mode));
213         if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum)))
214                 return rval;
215         XFS_STATS_INC(xs_dir_create);
216 
217         memset(&args, 0, sizeof(xfs_da_args_t));
218         args.name = name->name;
219         args.namelen = name->len;
220         args.filetype = name->type;
221         args.hashval = dp->i_mount->m_dirnameops->hashname(name);
222         args.inumber = inum;
223         args.dp = dp;
224         args.firstblock = first;
225         args.flist = flist;
226         args.total = total;
227         args.whichfork = XFS_DATA_FORK;
228         args.trans = tp;
229         args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
230 
231         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
232                 rval = xfs_dir2_sf_addname(&args);
233         else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
234                 return rval;
235         else if (v)
236                 rval = xfs_dir2_block_addname(&args);
237         else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
238                 return rval;
239         else if (v)
240                 rval = xfs_dir2_leaf_addname(&args);
241         else
242                 rval = xfs_dir2_node_addname(&args);
243         return rval;
244 }
245 
246 /*
247  * If doing a CI lookup and case-insensitive match, dup actual name into
248  * args.value. Return EEXIST for success (ie. name found) or an error.
249  */
250 int
251 xfs_dir_cilookup_result(
252         struct xfs_da_args *args,
253         const unsigned char *name,
254         int             len)
255 {
256         if (args->cmpresult == XFS_CMP_DIFFERENT)
257                 return ENOENT;
258         if (args->cmpresult != XFS_CMP_CASE ||
259                                         !(args->op_flags & XFS_DA_OP_CILOOKUP))
260                 return EEXIST;
261 
262         args->value = kmem_alloc(len, KM_NOFS | KM_MAYFAIL);
263         if (!args->value)
264                 return ENOMEM;
265 
266         memcpy(args->value, name, len);
267         args->valuelen = len;
268         return EEXIST;
269 }
270 
271 /*
272  * Lookup a name in a directory, give back the inode number.
273  * If ci_name is not NULL, returns the actual name in ci_name if it differs
274  * to name, or ci_name->name is set to NULL for an exact match.
275  */
276 
277 int
278 xfs_dir_lookup(
279         xfs_trans_t     *tp,
280         xfs_inode_t     *dp,
281         struct xfs_name *name,
282         xfs_ino_t       *inum,          /* out: inode number */
283         struct xfs_name *ci_name)       /* out: actual name if CI match */
284 {
285         xfs_da_args_t   args;
286         int             rval;
287         int             v;              /* type-checking value */
288 
289         ASSERT(S_ISDIR(dp->i_d.di_mode));
290         XFS_STATS_INC(xs_dir_lookup);
291 
292         memset(&args, 0, sizeof(xfs_da_args_t));
293         args.name = name->name;
294         args.namelen = name->len;
295         args.filetype = name->type;
296         args.hashval = dp->i_mount->m_dirnameops->hashname(name);
297         args.dp = dp;
298         args.whichfork = XFS_DATA_FORK;
299         args.trans = tp;
300         args.op_flags = XFS_DA_OP_OKNOENT;
301         if (ci_name)
302                 args.op_flags |= XFS_DA_OP_CILOOKUP;
303 
304         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
305                 rval = xfs_dir2_sf_lookup(&args);
306         else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
307                 return rval;
308         else if (v)
309                 rval = xfs_dir2_block_lookup(&args);
310         else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
311                 return rval;
312         else if (v)
313                 rval = xfs_dir2_leaf_lookup(&args);
314         else
315                 rval = xfs_dir2_node_lookup(&args);
316         if (rval == EEXIST)
317                 rval = 0;
318         if (!rval) {
319                 *inum = args.inumber;
320                 if (ci_name) {
321                         ci_name->name = args.value;
322                         ci_name->len = args.valuelen;
323                 }
324         }
325         return rval;
326 }
327 
328 /*
329  * Remove an entry from a directory.
330  */
331 int
332 xfs_dir_removename(
333         xfs_trans_t     *tp,
334         xfs_inode_t     *dp,
335         struct xfs_name *name,
336         xfs_ino_t       ino,
337         xfs_fsblock_t   *first,         /* bmap's firstblock */
338         xfs_bmap_free_t *flist,         /* bmap's freeblock list */
339         xfs_extlen_t    total)          /* bmap's total block count */
340 {
341         xfs_da_args_t   args;
342         int             rval;
343         int             v;              /* type-checking value */
344 
345         ASSERT(S_ISDIR(dp->i_d.di_mode));
346         XFS_STATS_INC(xs_dir_remove);
347 
348         memset(&args, 0, sizeof(xfs_da_args_t));
349         args.name = name->name;
350         args.namelen = name->len;
351         args.filetype = name->type;
352         args.hashval = dp->i_mount->m_dirnameops->hashname(name);
353         args.inumber = ino;
354         args.dp = dp;
355         args.firstblock = first;
356         args.flist = flist;
357         args.total = total;
358         args.whichfork = XFS_DATA_FORK;
359         args.trans = tp;
360 
361         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
362                 rval = xfs_dir2_sf_removename(&args);
363         else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
364                 return rval;
365         else if (v)
366                 rval = xfs_dir2_block_removename(&args);
367         else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
368                 return rval;
369         else if (v)
370                 rval = xfs_dir2_leaf_removename(&args);
371         else
372                 rval = xfs_dir2_node_removename(&args);
373         return rval;
374 }
375 
376 /*
377  * Replace the inode number of a directory entry.
378  */
379 int
380 xfs_dir_replace(
381         xfs_trans_t     *tp,
382         xfs_inode_t     *dp,
383         struct xfs_name *name,          /* name of entry to replace */
384         xfs_ino_t       inum,           /* new inode number */
385         xfs_fsblock_t   *first,         /* bmap's firstblock */
386         xfs_bmap_free_t *flist,         /* bmap's freeblock list */
387         xfs_extlen_t    total)          /* bmap's total block count */
388 {
389         xfs_da_args_t   args;
390         int             rval;
391         int             v;              /* type-checking value */
392 
393         ASSERT(S_ISDIR(dp->i_d.di_mode));
394 
395         if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum)))
396                 return rval;
397 
398         memset(&args, 0, sizeof(xfs_da_args_t));
399         args.name = name->name;
400         args.namelen = name->len;
401         args.filetype = name->type;
402         args.hashval = dp->i_mount->m_dirnameops->hashname(name);
403         args.inumber = inum;
404         args.dp = dp;
405         args.firstblock = first;
406         args.flist = flist;
407         args.total = total;
408         args.whichfork = XFS_DATA_FORK;
409         args.trans = tp;
410 
411         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
412                 rval = xfs_dir2_sf_replace(&args);
413         else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
414                 return rval;
415         else if (v)
416                 rval = xfs_dir2_block_replace(&args);
417         else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
418                 return rval;
419         else if (v)
420                 rval = xfs_dir2_leaf_replace(&args);
421         else
422                 rval = xfs_dir2_node_replace(&args);
423         return rval;
424 }
425 
426 /*
427  * See if this entry can be added to the directory without allocating space.
428  * First checks that the caller couldn't reserve enough space (resblks = 0).
429  */
430 int
431 xfs_dir_canenter(
432         xfs_trans_t     *tp,
433         xfs_inode_t     *dp,
434         struct xfs_name *name,          /* name of entry to add */
435         uint            resblks)
436 {
437         xfs_da_args_t   args;
438         int             rval;
439         int             v;              /* type-checking value */
440 
441         if (resblks)
442                 return 0;
443 
444         ASSERT(S_ISDIR(dp->i_d.di_mode));
445 
446         memset(&args, 0, sizeof(xfs_da_args_t));
447         args.name = name->name;
448         args.namelen = name->len;
449         args.filetype = name->type;
450         args.hashval = dp->i_mount->m_dirnameops->hashname(name);
451         args.dp = dp;
452         args.whichfork = XFS_DATA_FORK;
453         args.trans = tp;
454         args.op_flags = XFS_DA_OP_JUSTCHECK | XFS_DA_OP_ADDNAME |
455                                                         XFS_DA_OP_OKNOENT;
456 
457         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
458                 rval = xfs_dir2_sf_addname(&args);
459         else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
460                 return rval;
461         else if (v)
462                 rval = xfs_dir2_block_addname(&args);
463         else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
464                 return rval;
465         else if (v)
466                 rval = xfs_dir2_leaf_addname(&args);
467         else
468                 rval = xfs_dir2_node_addname(&args);
469         return rval;
470 }
471 
472 /*
473  * Utility routines.
474  */
475 
476 /*
477  * Add a block to the directory.
478  *
479  * This routine is for data and free blocks, not leaf/node blocks which are
480  * handled by xfs_da_grow_inode.
481  */
482 int
483 xfs_dir2_grow_inode(
484         struct xfs_da_args      *args,
485         int                     space,  /* v2 dir's space XFS_DIR2_xxx_SPACE */
486         xfs_dir2_db_t           *dbp)   /* out: block number added */
487 {
488         struct xfs_inode        *dp = args->dp;
489         struct xfs_mount        *mp = dp->i_mount;
490         xfs_fileoff_t           bno;    /* directory offset of new block */
491         int                     count;  /* count of filesystem blocks */
492         int                     error;
493 
494         trace_xfs_dir2_grow_inode(args, space);
495 
496         /*
497          * Set lowest possible block in the space requested.
498          */
499         bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE);
500         count = mp->m_dirblkfsbs;
501 
502         error = xfs_da_grow_inode_int(args, &bno, count);
503         if (error)
504                 return error;
505 
506         *dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno);
507 
508         /*
509          * Update file's size if this is the data space and it grew.
510          */
511         if (space == XFS_DIR2_DATA_SPACE) {
512                 xfs_fsize_t     size;           /* directory file (data) size */
513 
514                 size = XFS_FSB_TO_B(mp, bno + count);
515                 if (size > dp->i_d.di_size) {
516                         dp->i_d.di_size = size;
517                         xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
518                 }
519         }
520         return 0;
521 }
522 
523 /*
524  * See if the directory is a single-block form directory.
525  */
526 int
527 xfs_dir2_isblock(
528         xfs_trans_t     *tp,
529         xfs_inode_t     *dp,
530         int             *vp)            /* out: 1 is block, 0 is not block */
531 {
532         xfs_fileoff_t   last;           /* last file offset */
533         xfs_mount_t     *mp;
534         int             rval;
535 
536         mp = dp->i_mount;
537         if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK)))
538                 return rval;
539         rval = XFS_FSB_TO_B(mp, last) == mp->m_dirblksize;
540         ASSERT(rval == 0 || dp->i_d.di_size == mp->m_dirblksize);
541         *vp = rval;
542         return 0;
543 }
544 
545 /*
546  * See if the directory is a single-leaf form directory.
547  */
548 int
549 xfs_dir2_isleaf(
550         xfs_trans_t     *tp,
551         xfs_inode_t     *dp,
552         int             *vp)            /* out: 1 is leaf, 0 is not leaf */
553 {
554         xfs_fileoff_t   last;           /* last file offset */
555         xfs_mount_t     *mp;
556         int             rval;
557 
558         mp = dp->i_mount;
559         if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK)))
560                 return rval;
561         *vp = last == mp->m_dirleafblk + (1 << mp->m_sb.sb_dirblklog);
562         return 0;
563 }
564 
565 /*
566  * Remove the given block from the directory.
567  * This routine is used for data and free blocks, leaf/node are done
568  * by xfs_da_shrink_inode.
569  */
570 int
571 xfs_dir2_shrink_inode(
572         xfs_da_args_t   *args,
573         xfs_dir2_db_t   db,
574         struct xfs_buf  *bp)
575 {
576         xfs_fileoff_t   bno;            /* directory file offset */
577         xfs_dablk_t     da;             /* directory file offset */
578         int             done;           /* bunmap is finished */
579         xfs_inode_t     *dp;
580         int             error;
581         xfs_mount_t     *mp;
582         xfs_trans_t     *tp;
583 
584         trace_xfs_dir2_shrink_inode(args, db);
585 
586         dp = args->dp;
587         mp = dp->i_mount;
588         tp = args->trans;
589         da = xfs_dir2_db_to_da(mp, db);
590         /*
591          * Unmap the fsblock(s).
592          */
593         if ((error = xfs_bunmapi(tp, dp, da, mp->m_dirblkfsbs,
594                         XFS_BMAPI_METADATA, 0, args->firstblock, args->flist,
595                         &done))) {
596                 /*
597                  * ENOSPC actually can happen if we're in a removename with
598                  * no space reservation, and the resulting block removal
599                  * would cause a bmap btree split or conversion from extents
600                  * to btree.  This can only happen for un-fragmented
601                  * directory blocks, since you need to be punching out
602                  * the middle of an extent.
603                  * In this case we need to leave the block in the file,
604                  * and not binval it.
605                  * So the block has to be in a consistent empty state
606                  * and appropriately logged.
607                  * We don't free up the buffer, the caller can tell it
608                  * hasn't happened since it got an error back.
609                  */
610                 return error;
611         }
612         ASSERT(done);
613         /*
614          * Invalidate the buffer from the transaction.
615          */
616         xfs_trans_binval(tp, bp);
617         /*
618          * If it's not a data block, we're done.
619          */
620         if (db >= XFS_DIR2_LEAF_FIRSTDB(mp))
621                 return 0;
622         /*
623          * If the block isn't the last one in the directory, we're done.
624          */
625         if (dp->i_d.di_size > xfs_dir2_db_off_to_byte(mp, db + 1, 0))
626                 return 0;
627         bno = da;
628         if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) {
629                 /*
630                  * This can't really happen unless there's kernel corruption.
631                  */
632                 return error;
633         }
634         if (db == mp->m_dirdatablk)
635                 ASSERT(bno == 0);
636         else
637                 ASSERT(bno > 0);
638         /*
639          * Set the size to the new last block.
640          */
641         dp->i_d.di_size = XFS_FSB_TO_B(mp, bno);
642         xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
643         return 0;
644 }
645 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp