blob: 59169aff30fef499014e79c5e437137410e1ee32 [file] [log] [blame]
Dave Chinner0b61f8a2018-06-05 19:42:14 -07001// SPDX-License-Identifier: GPL-2.0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
Nathan Scott7b718762005-11-02 14:58:39 +11003 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006#include "xfs.h"
Nathan Scotta844f452005-11-02 14:38:42 +11007#include "xfs_fs.h"
Dave Chinnera4fbe6a2013-10-23 10:51:50 +11008#include "xfs_format.h"
Dave Chinner239880e2013-10-23 10:50:10 +11009#include "xfs_log_format.h"
10#include "xfs_trans_resv.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include "xfs_mount.h"
Darrick J. Wong3ab78df2016-08-03 11:15:38 +100012#include "xfs_defer.h"
Dave Chinner57062782013-10-15 09:17:51 +110013#include "xfs_da_format.h"
Nathan Scotta844f452005-11-02 14:38:42 +110014#include "xfs_da_btree.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include "xfs_inode.h"
Dave Chinner239880e2013-10-23 10:50:10 +110016#include "xfs_trans.h"
Nathan Scotta844f452005-11-02 14:38:42 +110017#include "xfs_inode_item.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include "xfs_bmap.h"
Dave Chinner2b9ab5a2013-08-12 20:49:37 +100019#include "xfs_dir2.h"
Christoph Hellwig57926642011-07-13 13:43:48 +020020#include "xfs_dir2_priv.h"
Darrick J. Wong91fb9af2017-10-17 21:37:34 -070021#include "xfs_ialloc.h"
Darrick J. Wonge9e899a2017-10-31 12:04:49 -070022#include "xfs_errortag.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include "xfs_error.h"
Christoph Hellwig0b1b2132009-12-14 23:14:59 +000024#include "xfs_trace.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
Dave Chinner0cb97762013-08-12 20:50:09 +100026struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR };
27
Dave Chinner1b767ee2014-12-04 09:43:17 +110028/*
Amir Goldstein1fc4d332017-01-17 11:41:43 -080029 * Convert inode mode to directory entry filetype
Dave Chinner1b767ee2014-12-04 09:43:17 +110030 */
Darrick J. Wonga5c46e52017-10-17 21:37:44 -070031unsigned char
32xfs_mode_to_ftype(
33 int mode)
Amir Goldstein1fc4d332017-01-17 11:41:43 -080034{
35 switch (mode & S_IFMT) {
36 case S_IFREG:
37 return XFS_DIR3_FT_REG_FILE;
38 case S_IFDIR:
39 return XFS_DIR3_FT_DIR;
40 case S_IFCHR:
41 return XFS_DIR3_FT_CHRDEV;
42 case S_IFBLK:
43 return XFS_DIR3_FT_BLKDEV;
44 case S_IFIFO:
45 return XFS_DIR3_FT_FIFO;
46 case S_IFSOCK:
47 return XFS_DIR3_FT_SOCK;
48 case S_IFLNK:
49 return XFS_DIR3_FT_SYMLINK;
50 default:
51 return XFS_DIR3_FT_UNKNOWN;
52 }
53}
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
Barry Naujok189f4bf2008-05-21 16:58:55 +100055/*
56 * ASCII case-insensitive (ie. A-Z) support for directories that was
57 * used in IRIX.
58 */
59STATIC xfs_dahash_t
60xfs_ascii_ci_hashname(
61 struct xfs_name *name)
62{
63 xfs_dahash_t hash;
64 int i;
65
66 for (i = 0, hash = 0; i < name->len; i++)
67 hash = tolower(name->name[i]) ^ rol32(hash, 7);
68
69 return hash;
70}
71
72STATIC enum xfs_dacmp
73xfs_ascii_ci_compname(
74 struct xfs_da_args *args,
Dave Chinner2bc75422010-01-20 10:47:17 +110075 const unsigned char *name,
76 int len)
Barry Naujok189f4bf2008-05-21 16:58:55 +100077{
78 enum xfs_dacmp result;
79 int i;
80
81 if (args->namelen != len)
82 return XFS_CMP_DIFFERENT;
83
84 result = XFS_CMP_EXACT;
85 for (i = 0; i < len; i++) {
86 if (args->name[i] == name[i])
87 continue;
88 if (tolower(args->name[i]) != tolower(name[i]))
89 return XFS_CMP_DIFFERENT;
90 result = XFS_CMP_CASE;
91 }
92
93 return result;
94}
95
Bhumika Goyalcf7841c2016-11-28 14:57:42 +110096static const struct xfs_nameops xfs_ascii_ci_nameops = {
Barry Naujok189f4bf2008-05-21 16:58:55 +100097 .hashname = xfs_ascii_ci_hashname,
98 .compname = xfs_ascii_ci_compname,
99};
100
Dave Chinner0650b552014-06-06 15:01:58 +1000101int
102xfs_da_mount(
103 struct xfs_mount *mp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104{
Dave Chinner0650b552014-06-06 15:01:58 +1000105 struct xfs_da_geometry *dageo;
106 int nodehdr_size;
Dave Chinner37804372013-08-26 14:13:30 +1000107
108
Dave Chinner5d074a42014-05-20 07:46:55 +1000109 ASSERT(mp->m_sb.sb_versionnum & XFS_SB_VERSION_DIRV2BIT);
Darrick J. Wongac503a42018-01-08 10:51:27 -0800110 ASSERT(xfs_dir2_dirblock_bytes(&mp->m_sb) <= XFS_MAX_BLOCKSIZE);
Dave Chinner4bceb182013-10-29 22:11:51 +1100111
112 mp->m_dir_inode_ops = xfs_dir_get_ops(mp, NULL);
113 mp->m_nondir_inode_ops = xfs_nondir_get_ops(mp, NULL);
114
Dave Chinner1c9a5b22013-10-30 09:15:02 +1100115 nodehdr_size = mp->m_dir_inode_ops->node_hdr_size;
Dave Chinner0650b552014-06-06 15:01:58 +1000116 mp->m_dir_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
117 KM_SLEEP | KM_MAYFAIL);
118 mp->m_attr_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
119 KM_SLEEP | KM_MAYFAIL);
120 if (!mp->m_dir_geo || !mp->m_attr_geo) {
121 kmem_free(mp->m_dir_geo);
122 kmem_free(mp->m_attr_geo);
Dave Chinner24513372014-06-25 14:58:08 +1000123 return -ENOMEM;
Dave Chinner0650b552014-06-06 15:01:58 +1000124 }
Dave Chinner37804372013-08-26 14:13:30 +1000125
Dave Chinner0650b552014-06-06 15:01:58 +1000126 /* set up directory geometry */
127 dageo = mp->m_dir_geo;
128 dageo->blklog = mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog;
129 dageo->fsblog = mp->m_sb.sb_blocklog;
Darrick J. Wongac503a42018-01-08 10:51:27 -0800130 dageo->blksize = xfs_dir2_dirblock_bytes(&mp->m_sb);
Dave Chinner0650b552014-06-06 15:01:58 +1000131 dageo->fsbcount = 1 << mp->m_sb.sb_dirblklog;
Dave Chinner30028032014-06-06 15:08:18 +1000132
133 /*
134 * Now we've set up the block conversion variables, we can calculate the
135 * segment block constants using the geometry structure.
136 */
137 dageo->datablk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_DATA_OFFSET);
138 dageo->leafblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_LEAF_OFFSET);
139 dageo->freeblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_FREE_OFFSET);
Dave Chinner0650b552014-06-06 15:01:58 +1000140 dageo->node_ents = (dageo->blksize - nodehdr_size) /
141 (uint)sizeof(xfs_da_node_entry_t);
142 dageo->magicpct = (dageo->blksize * 37) / 100;
143
144 /* set up attribute geometry - single fsb only */
145 dageo = mp->m_attr_geo;
146 dageo->blklog = mp->m_sb.sb_blocklog;
147 dageo->fsblog = mp->m_sb.sb_blocklog;
148 dageo->blksize = 1 << dageo->blklog;
149 dageo->fsbcount = 1;
150 dageo->node_ents = (dageo->blksize - nodehdr_size) /
151 (uint)sizeof(xfs_da_node_entry_t);
152 dageo->magicpct = (dageo->blksize * 37) / 100;
153
Barry Naujok189f4bf2008-05-21 16:58:55 +1000154 if (xfs_sb_version_hasasciici(&mp->m_sb))
155 mp->m_dirnameops = &xfs_ascii_ci_nameops;
156 else
157 mp->m_dirnameops = &xfs_default_nameops;
Dave Chinner32c54832013-10-29 22:11:46 +1100158
Dave Chinner0650b552014-06-06 15:01:58 +1000159 return 0;
160}
161
162void
163xfs_da_unmount(
164 struct xfs_mount *mp)
165{
166 kmem_free(mp->m_dir_geo);
167 kmem_free(mp->m_attr_geo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168}
169
170/*
171 * Return 1 if directory contains only "." and "..".
172 */
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000173int
174xfs_dir_isempty(
175 xfs_inode_t *dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176{
Christoph Hellwigac8ba502011-07-08 14:35:13 +0200177 xfs_dir2_sf_hdr_t *sfp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Dave Chinnerc19b3b052016-02-09 16:54:58 +1100179 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000180 if (dp->i_d.di_size == 0) /* might happen during shutdown. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp))
183 return 0;
Christoph Hellwigac8ba502011-07-08 14:35:13 +0200184 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
185 return !sfp->count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186}
187
188/*
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000189 * Validate a given inode number.
190 */
191int
192xfs_dir_ino_validate(
193 xfs_mount_t *mp,
194 xfs_ino_t ino)
195{
Darrick J. Wong91fb9af2017-10-17 21:37:34 -0700196 bool ino_ok = xfs_verify_dir_ino(mp, ino);
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000197
Darrick J. Wong9e24cfd2017-06-20 17:54:47 -0700198 if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE))) {
Dave Chinner53487782011-03-07 10:05:35 +1100199 xfs_warn(mp, "Invalid inode number 0x%Lx",
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000200 (unsigned long long) ino);
201 XFS_ERROR_REPORT("xfs_dir_ino_validate", XFS_ERRLEVEL_LOW, mp);
Dave Chinner24513372014-06-25 14:58:08 +1000202 return -EFSCORRUPTED;
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000203 }
204 return 0;
205}
206
207/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 * Initialize a directory with its "." and ".." entries.
209 */
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000210int
211xfs_dir_init(
212 xfs_trans_t *tp,
213 xfs_inode_t *dp,
214 xfs_inode_t *pdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215{
Dave Chinnera1358aa2014-02-27 16:51:26 +1100216 struct xfs_da_args *args;
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000217 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
Dave Chinnerc19b3b052016-02-09 16:54:58 +1100219 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
Dave Chinnera1358aa2014-02-27 16:51:26 +1100220 error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino);
221 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 return error;
Dave Chinnera1358aa2014-02-27 16:51:26 +1100223
224 args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
225 if (!args)
Dave Chinner24513372014-06-25 14:58:08 +1000226 return -ENOMEM;
Dave Chinnera1358aa2014-02-27 16:51:26 +1100227
Dave Chinner0650b552014-06-06 15:01:58 +1000228 args->geo = dp->i_mount->m_dir_geo;
Dave Chinnera1358aa2014-02-27 16:51:26 +1100229 args->dp = dp;
230 args->trans = tp;
231 error = xfs_dir2_sf_create(args, pdp->i_ino);
232 kmem_free(args);
233 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234}
235
236/*
Eric Sandeenb16ed7c2014-09-09 11:58:07 +1000237 * Enter a name in a directory, or check for available space.
238 * If inum is 0, only the available space test is performed.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 */
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000240int
241xfs_dir_createname(
242 xfs_trans_t *tp,
243 xfs_inode_t *dp,
Barry Naujok556b8b12008-04-10 12:22:07 +1000244 struct xfs_name *name,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 xfs_ino_t inum, /* new entry inode number */
246 xfs_fsblock_t *first, /* bmap's firstblock */
Darrick J. Wong2c3234d2016-08-03 11:19:29 +1000247 struct xfs_defer_ops *dfops, /* bmap's freeblock list */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 xfs_extlen_t total) /* bmap's total block count */
249{
Dave Chinnera1358aa2014-02-27 16:51:26 +1100250 struct xfs_da_args *args;
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000251 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 int v; /* type-checking value */
253
Dave Chinnerc19b3b052016-02-09 16:54:58 +1100254 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
Eric Sandeenb16ed7c2014-09-09 11:58:07 +1000255 if (inum) {
256 rval = xfs_dir_ino_validate(tp->t_mountp, inum);
257 if (rval)
258 return rval;
Bill O'Donnellff6d6af2015-10-12 18:21:22 +1100259 XFS_STATS_INC(dp->i_mount, xs_dir_create);
Eric Sandeenb16ed7c2014-09-09 11:58:07 +1000260 }
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000261
Dave Chinnera1358aa2014-02-27 16:51:26 +1100262 args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
263 if (!args)
Dave Chinner24513372014-06-25 14:58:08 +1000264 return -ENOMEM;
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000265
Dave Chinner0650b552014-06-06 15:01:58 +1000266 args->geo = dp->i_mount->m_dir_geo;
Dave Chinnera1358aa2014-02-27 16:51:26 +1100267 args->name = name->name;
268 args->namelen = name->len;
269 args->filetype = name->type;
270 args->hashval = dp->i_mount->m_dirnameops->hashname(name);
271 args->inumber = inum;
272 args->dp = dp;
273 args->firstblock = first;
Darrick J. Wong2c3234d2016-08-03 11:19:29 +1000274 args->dfops = dfops;
Dave Chinnera1358aa2014-02-27 16:51:26 +1100275 args->total = total;
276 args->whichfork = XFS_DATA_FORK;
277 args->trans = tp;
278 args->op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
Eric Sandeenb16ed7c2014-09-09 11:58:07 +1000279 if (!inum)
280 args->op_flags |= XFS_DA_OP_JUSTCHECK;
Dave Chinnera1358aa2014-02-27 16:51:26 +1100281
282 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
283 rval = xfs_dir2_sf_addname(args);
284 goto out_free;
285 }
286
Dave Chinner53f82db2014-06-06 15:20:32 +1000287 rval = xfs_dir2_isblock(args, &v);
Dave Chinnera1358aa2014-02-27 16:51:26 +1100288 if (rval)
289 goto out_free;
290 if (v) {
291 rval = xfs_dir2_block_addname(args);
292 goto out_free;
293 }
294
Dave Chinner53f82db2014-06-06 15:20:32 +1000295 rval = xfs_dir2_isleaf(args, &v);
Dave Chinnera1358aa2014-02-27 16:51:26 +1100296 if (rval)
297 goto out_free;
298 if (v)
299 rval = xfs_dir2_leaf_addname(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 else
Dave Chinnera1358aa2014-02-27 16:51:26 +1100301 rval = xfs_dir2_node_addname(args);
302
303out_free:
304 kmem_free(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 return rval;
306}
307
308/*
Barry Naujok384f3ce2008-05-21 16:58:22 +1000309 * If doing a CI lookup and case-insensitive match, dup actual name into
310 * args.value. Return EEXIST for success (ie. name found) or an error.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 */
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000312int
Barry Naujok384f3ce2008-05-21 16:58:22 +1000313xfs_dir_cilookup_result(
314 struct xfs_da_args *args,
Dave Chinnera3380ae2010-01-20 10:47:25 +1100315 const unsigned char *name,
Barry Naujok384f3ce2008-05-21 16:58:22 +1000316 int len)
317{
318 if (args->cmpresult == XFS_CMP_DIFFERENT)
Dave Chinner24513372014-06-25 14:58:08 +1000319 return -ENOENT;
Barry Naujok384f3ce2008-05-21 16:58:22 +1000320 if (args->cmpresult != XFS_CMP_CASE ||
321 !(args->op_flags & XFS_DA_OP_CILOOKUP))
Dave Chinner24513372014-06-25 14:58:08 +1000322 return -EEXIST;
Barry Naujok384f3ce2008-05-21 16:58:22 +1000323
Christoph Hellwig3f52c2f2009-07-18 18:14:57 -0400324 args->value = kmem_alloc(len, KM_NOFS | KM_MAYFAIL);
Barry Naujok384f3ce2008-05-21 16:58:22 +1000325 if (!args->value)
Dave Chinner24513372014-06-25 14:58:08 +1000326 return -ENOMEM;
Barry Naujok384f3ce2008-05-21 16:58:22 +1000327
328 memcpy(args->value, name, len);
329 args->valuelen = len;
Dave Chinner24513372014-06-25 14:58:08 +1000330 return -EEXIST;
Barry Naujok384f3ce2008-05-21 16:58:22 +1000331}
332
333/*
334 * Lookup a name in a directory, give back the inode number.
335 * If ci_name is not NULL, returns the actual name in ci_name if it differs
336 * to name, or ci_name->name is set to NULL for an exact match.
337 */
338
339int
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000340xfs_dir_lookup(
341 xfs_trans_t *tp,
342 xfs_inode_t *dp,
Barry Naujok556b8b12008-04-10 12:22:07 +1000343 struct xfs_name *name,
Barry Naujok384f3ce2008-05-21 16:58:22 +1000344 xfs_ino_t *inum, /* out: inode number */
345 struct xfs_name *ci_name) /* out: actual name if CI match */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346{
Dave Chinnera1358aa2014-02-27 16:51:26 +1100347 struct xfs_da_args *args;
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000348 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 int v; /* type-checking value */
Dave Chinnerdbad7c92015-08-19 10:33:00 +1000350 int lock_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Dave Chinnerc19b3b052016-02-09 16:54:58 +1100352 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
Bill O'Donnellff6d6af2015-10-12 18:21:22 +1100353 XFS_STATS_INC(dp->i_mount, xs_dir_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
Dave Chinnera1358aa2014-02-27 16:51:26 +1100355 /*
356 * We need to use KM_NOFS here so that lockdep will not throw false
357 * positive deadlock warnings on a non-transactional lookup path. It is
358 * safe to recurse into inode recalim in that case, but lockdep can't
359 * easily be taught about it. Hence KM_NOFS avoids having to add more
360 * lockdep Doing this avoids having to add a bunch of lockdep class
361 * annotations into the reclaim path for the ilock.
362 */
363 args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
Dave Chinner0650b552014-06-06 15:01:58 +1000364 args->geo = dp->i_mount->m_dir_geo;
Dave Chinnera1358aa2014-02-27 16:51:26 +1100365 args->name = name->name;
366 args->namelen = name->len;
367 args->filetype = name->type;
368 args->hashval = dp->i_mount->m_dirnameops->hashname(name);
369 args->dp = dp;
370 args->whichfork = XFS_DATA_FORK;
371 args->trans = tp;
372 args->op_flags = XFS_DA_OP_OKNOENT;
Barry Naujok384f3ce2008-05-21 16:58:22 +1000373 if (ci_name)
Dave Chinnera1358aa2014-02-27 16:51:26 +1100374 args->op_flags |= XFS_DA_OP_CILOOKUP;
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000375
Dave Chinnerdbad7c92015-08-19 10:33:00 +1000376 lock_mode = xfs_ilock_data_map_shared(dp);
Dave Chinnera1358aa2014-02-27 16:51:26 +1100377 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
378 rval = xfs_dir2_sf_lookup(args);
379 goto out_check_rval;
380 }
381
Dave Chinner53f82db2014-06-06 15:20:32 +1000382 rval = xfs_dir2_isblock(args, &v);
Dave Chinnera1358aa2014-02-27 16:51:26 +1100383 if (rval)
384 goto out_free;
385 if (v) {
386 rval = xfs_dir2_block_lookup(args);
387 goto out_check_rval;
388 }
389
Dave Chinner53f82db2014-06-06 15:20:32 +1000390 rval = xfs_dir2_isleaf(args, &v);
Dave Chinnera1358aa2014-02-27 16:51:26 +1100391 if (rval)
392 goto out_free;
393 if (v)
394 rval = xfs_dir2_leaf_lookup(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 else
Dave Chinnera1358aa2014-02-27 16:51:26 +1100396 rval = xfs_dir2_node_lookup(args);
397
398out_check_rval:
Dave Chinner24513372014-06-25 14:58:08 +1000399 if (rval == -EEXIST)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 rval = 0;
Barry Naujok384f3ce2008-05-21 16:58:22 +1000401 if (!rval) {
Dave Chinnera1358aa2014-02-27 16:51:26 +1100402 *inum = args->inumber;
Barry Naujok384f3ce2008-05-21 16:58:22 +1000403 if (ci_name) {
Dave Chinnera1358aa2014-02-27 16:51:26 +1100404 ci_name->name = args->value;
405 ci_name->len = args->valuelen;
Barry Naujok384f3ce2008-05-21 16:58:22 +1000406 }
407 }
Dave Chinnera1358aa2014-02-27 16:51:26 +1100408out_free:
Dave Chinnerdbad7c92015-08-19 10:33:00 +1000409 xfs_iunlock(dp, lock_mode);
Dave Chinnera1358aa2014-02-27 16:51:26 +1100410 kmem_free(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 return rval;
412}
413
414/*
415 * Remove an entry from a directory.
416 */
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000417int
418xfs_dir_removename(
419 xfs_trans_t *tp,
420 xfs_inode_t *dp,
Barry Naujok556b8b12008-04-10 12:22:07 +1000421 struct xfs_name *name,
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000422 xfs_ino_t ino,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 xfs_fsblock_t *first, /* bmap's firstblock */
Darrick J. Wong2c3234d2016-08-03 11:19:29 +1000424 struct xfs_defer_ops *dfops, /* bmap's freeblock list */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 xfs_extlen_t total) /* bmap's total block count */
426{
Dave Chinnera1358aa2014-02-27 16:51:26 +1100427 struct xfs_da_args *args;
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000428 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 int v; /* type-checking value */
430
Dave Chinnerc19b3b052016-02-09 16:54:58 +1100431 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
Bill O'Donnellff6d6af2015-10-12 18:21:22 +1100432 XFS_STATS_INC(dp->i_mount, xs_dir_remove);
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000433
Dave Chinnera1358aa2014-02-27 16:51:26 +1100434 args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
435 if (!args)
Dave Chinner24513372014-06-25 14:58:08 +1000436 return -ENOMEM;
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000437
Dave Chinner0650b552014-06-06 15:01:58 +1000438 args->geo = dp->i_mount->m_dir_geo;
Dave Chinnera1358aa2014-02-27 16:51:26 +1100439 args->name = name->name;
440 args->namelen = name->len;
441 args->filetype = name->type;
442 args->hashval = dp->i_mount->m_dirnameops->hashname(name);
443 args->inumber = ino;
444 args->dp = dp;
445 args->firstblock = first;
Darrick J. Wong2c3234d2016-08-03 11:19:29 +1000446 args->dfops = dfops;
Dave Chinnera1358aa2014-02-27 16:51:26 +1100447 args->total = total;
448 args->whichfork = XFS_DATA_FORK;
449 args->trans = tp;
450
451 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
452 rval = xfs_dir2_sf_removename(args);
453 goto out_free;
454 }
455
Dave Chinner53f82db2014-06-06 15:20:32 +1000456 rval = xfs_dir2_isblock(args, &v);
Dave Chinnera1358aa2014-02-27 16:51:26 +1100457 if (rval)
458 goto out_free;
459 if (v) {
460 rval = xfs_dir2_block_removename(args);
461 goto out_free;
462 }
463
Dave Chinner53f82db2014-06-06 15:20:32 +1000464 rval = xfs_dir2_isleaf(args, &v);
Dave Chinnera1358aa2014-02-27 16:51:26 +1100465 if (rval)
466 goto out_free;
467 if (v)
468 rval = xfs_dir2_leaf_removename(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 else
Dave Chinnera1358aa2014-02-27 16:51:26 +1100470 rval = xfs_dir2_node_removename(args);
471out_free:
472 kmem_free(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 return rval;
474}
475
476/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 * Replace the inode number of a directory entry.
478 */
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000479int
480xfs_dir_replace(
481 xfs_trans_t *tp,
482 xfs_inode_t *dp,
Barry Naujok556b8b12008-04-10 12:22:07 +1000483 struct xfs_name *name, /* name of entry to replace */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 xfs_ino_t inum, /* new inode number */
485 xfs_fsblock_t *first, /* bmap's firstblock */
Darrick J. Wong2c3234d2016-08-03 11:19:29 +1000486 struct xfs_defer_ops *dfops, /* bmap's freeblock list */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 xfs_extlen_t total) /* bmap's total block count */
488{
Dave Chinnera1358aa2014-02-27 16:51:26 +1100489 struct xfs_da_args *args;
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000490 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 int v; /* type-checking value */
492
Dave Chinnerc19b3b052016-02-09 16:54:58 +1100493 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
Dave Chinnera1358aa2014-02-27 16:51:26 +1100495 rval = xfs_dir_ino_validate(tp->t_mountp, inum);
496 if (rval)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 return rval;
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000498
Dave Chinnera1358aa2014-02-27 16:51:26 +1100499 args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
500 if (!args)
Dave Chinner24513372014-06-25 14:58:08 +1000501 return -ENOMEM;
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000502
Dave Chinner0650b552014-06-06 15:01:58 +1000503 args->geo = dp->i_mount->m_dir_geo;
Dave Chinnera1358aa2014-02-27 16:51:26 +1100504 args->name = name->name;
505 args->namelen = name->len;
506 args->filetype = name->type;
507 args->hashval = dp->i_mount->m_dirnameops->hashname(name);
508 args->inumber = inum;
509 args->dp = dp;
510 args->firstblock = first;
Darrick J. Wong2c3234d2016-08-03 11:19:29 +1000511 args->dfops = dfops;
Dave Chinnera1358aa2014-02-27 16:51:26 +1100512 args->total = total;
513 args->whichfork = XFS_DATA_FORK;
514 args->trans = tp;
515
516 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
517 rval = xfs_dir2_sf_replace(args);
518 goto out_free;
519 }
520
Dave Chinner53f82db2014-06-06 15:20:32 +1000521 rval = xfs_dir2_isblock(args, &v);
Dave Chinnera1358aa2014-02-27 16:51:26 +1100522 if (rval)
523 goto out_free;
524 if (v) {
525 rval = xfs_dir2_block_replace(args);
526 goto out_free;
527 }
528
Dave Chinner53f82db2014-06-06 15:20:32 +1000529 rval = xfs_dir2_isleaf(args, &v);
Dave Chinnera1358aa2014-02-27 16:51:26 +1100530 if (rval)
531 goto out_free;
532 if (v)
533 rval = xfs_dir2_leaf_replace(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 else
Dave Chinnera1358aa2014-02-27 16:51:26 +1100535 rval = xfs_dir2_node_replace(args);
536out_free:
537 kmem_free(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 return rval;
539}
540
541/*
542 * See if this entry can be added to the directory without allocating space.
543 */
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000544int
545xfs_dir_canenter(
546 xfs_trans_t *tp,
547 xfs_inode_t *dp,
Eric Sandeen94f3cad2014-09-09 11:57:52 +1000548 struct xfs_name *name) /* name of entry to add */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549{
Eric Sandeenb16ed7c2014-09-09 11:58:07 +1000550 return xfs_dir_createname(tp, dp, name, 0, NULL, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551}
552
553/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 * Utility routines.
555 */
556
557/*
558 * Add a block to the directory.
Christoph Hellwig77936d02011-07-13 13:43:49 +0200559 *
560 * This routine is for data and free blocks, not leaf/node blocks which are
561 * handled by xfs_da_grow_inode.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 */
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000563int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564xfs_dir2_grow_inode(
Christoph Hellwig77936d02011-07-13 13:43:49 +0200565 struct xfs_da_args *args,
566 int space, /* v2 dir's space XFS_DIR2_xxx_SPACE */
567 xfs_dir2_db_t *dbp) /* out: block number added */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568{
Christoph Hellwig77936d02011-07-13 13:43:49 +0200569 struct xfs_inode *dp = args->dp;
570 struct xfs_mount *mp = dp->i_mount;
571 xfs_fileoff_t bno; /* directory offset of new block */
572 int count; /* count of filesystem blocks */
573 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
Christoph Hellwig0b1b2132009-12-14 23:14:59 +0000575 trace_xfs_dir2_grow_inode(args, space);
576
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 /*
578 * Set lowest possible block in the space requested.
579 */
580 bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE);
Dave Chinnerd6cf1302014-06-06 15:14:11 +1000581 count = args->geo->fsbcount;
Christoph Hellwig77936d02011-07-13 13:43:49 +0200582
583 error = xfs_da_grow_inode_int(args, &bno, count);
584 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
Dave Chinner2998ab1d2014-06-06 15:07:53 +1000587 *dbp = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)bno);
David Chinnera7444052008-10-30 17:38:12 +1100588
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 /*
590 * Update file's size if this is the data space and it grew.
591 */
592 if (space == XFS_DIR2_DATA_SPACE) {
593 xfs_fsize_t size; /* directory file (data) size */
594
595 size = XFS_FSB_TO_B(mp, bno + count);
596 if (size > dp->i_d.di_size) {
597 dp->i_d.di_size = size;
Christoph Hellwig77936d02011-07-13 13:43:49 +0200598 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 }
600 }
601 return 0;
602}
603
604/*
605 * See if the directory is a single-block form directory.
606 */
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000607int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608xfs_dir2_isblock(
Dave Chinner53f82db2014-06-06 15:20:32 +1000609 struct xfs_da_args *args,
610 int *vp) /* out: 1 is block, 0 is not block */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611{
Dave Chinner53f82db2014-06-06 15:20:32 +1000612 xfs_fileoff_t last; /* last file offset */
613 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
Dave Chinner53f82db2014-06-06 15:20:32 +1000615 if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 return rval;
Dave Chinner53f82db2014-06-06 15:20:32 +1000617 rval = XFS_FSB_TO_B(args->dp->i_mount, last) == args->geo->blksize;
Amir Goldstein3c6f46e2017-01-17 11:41:41 -0800618 if (rval != 0 && args->dp->i_d.di_size != args->geo->blksize)
619 return -EFSCORRUPTED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 *vp = rval;
621 return 0;
622}
623
624/*
625 * See if the directory is a single-leaf form directory.
626 */
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000627int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628xfs_dir2_isleaf(
Dave Chinner53f82db2014-06-06 15:20:32 +1000629 struct xfs_da_args *args,
630 int *vp) /* out: 1 is block, 0 is not block */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631{
Dave Chinner53f82db2014-06-06 15:20:32 +1000632 xfs_fileoff_t last; /* last file offset */
633 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
Dave Chinner53f82db2014-06-06 15:20:32 +1000635 if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 return rval;
Dave Chinner53f82db2014-06-06 15:20:32 +1000637 *vp = last == args->geo->leafblk + args->geo->fsbcount;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 return 0;
639}
640
641/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 * Remove the given block from the directory.
643 * This routine is used for data and free blocks, leaf/node are done
644 * by xfs_da_shrink_inode.
645 */
646int
647xfs_dir2_shrink_inode(
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000648 xfs_da_args_t *args,
649 xfs_dir2_db_t db,
Dave Chinner1d9025e2012-06-22 18:50:14 +1000650 struct xfs_buf *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651{
652 xfs_fileoff_t bno; /* directory file offset */
653 xfs_dablk_t da; /* directory file offset */
654 int done; /* bunmap is finished */
Nathan Scottf6c2d1f2006-06-20 13:04:51 +1000655 xfs_inode_t *dp;
656 int error;
657 xfs_mount_t *mp;
658 xfs_trans_t *tp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Christoph Hellwig0b1b2132009-12-14 23:14:59 +0000660 trace_xfs_dir2_shrink_inode(args, db);
661
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 dp = args->dp;
663 mp = dp->i_mount;
664 tp = args->trans;
Dave Chinner2998ab1d2014-06-06 15:07:53 +1000665 da = xfs_dir2_db_to_da(args->geo, db);
Dave Chinnerab7bb612015-07-29 11:51:01 +1000666
667 /* Unmap the fsblock(s). */
668 error = xfs_bunmapi(tp, dp, da, args->geo->fsbcount, 0, 0,
Darrick J. Wong2c3234d2016-08-03 11:19:29 +1000669 args->firstblock, args->dfops, &done);
Dave Chinnerab7bb612015-07-29 11:51:01 +1000670 if (error) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 /*
Dave Chinnerab7bb612015-07-29 11:51:01 +1000672 * ENOSPC actually can happen if we're in a removename with no
673 * space reservation, and the resulting block removal would
674 * cause a bmap btree split or conversion from extents to btree.
675 * This can only happen for un-fragmented directory blocks,
676 * since you need to be punching out the middle of an extent.
677 * In this case we need to leave the block in the file, and not
678 * binval it. So the block has to be in a consistent empty
679 * state and appropriately logged. We don't free up the buffer,
680 * the caller can tell it hasn't happened since it got an error
681 * back.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 */
683 return error;
684 }
685 ASSERT(done);
686 /*
687 * Invalidate the buffer from the transaction.
688 */
Dave Chinner1d9025e2012-06-22 18:50:14 +1000689 xfs_trans_binval(tp, bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 /*
691 * If it's not a data block, we're done.
692 */
Dave Chinner30028032014-06-06 15:08:18 +1000693 if (db >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 return 0;
695 /*
696 * If the block isn't the last one in the directory, we're done.
697 */
Dave Chinner9b3b5522014-06-06 15:06:53 +1000698 if (dp->i_d.di_size > xfs_dir2_db_off_to_byte(args->geo, db + 1, 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 return 0;
700 bno = da;
701 if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) {
702 /*
703 * This can't really happen unless there's kernel corruption.
704 */
705 return error;
706 }
Dave Chinner7dda6e82014-06-06 15:11:18 +1000707 if (db == args->geo->datablk)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 ASSERT(bno == 0);
709 else
710 ASSERT(bno > 0);
711 /*
712 * Set the size to the new last block.
713 */
714 dp->i_d.di_size = XFS_FSB_TO_B(mp, bno);
715 xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
716 return 0;
717}