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

TOMOYO Linux Cross Reference
Linux/fs/xfs/libxfs/xfs_parent.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ 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.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * Copyright (c) 2022-2024 Oracle.
  4  * All rights reserved.
  5  */
  6 #include "xfs.h"
  7 #include "xfs_fs.h"
  8 #include "xfs_format.h"
  9 #include "xfs_da_format.h"
 10 #include "xfs_log_format.h"
 11 #include "xfs_shared.h"
 12 #include "xfs_trans_resv.h"
 13 #include "xfs_mount.h"
 14 #include "xfs_bmap_btree.h"
 15 #include "xfs_inode.h"
 16 #include "xfs_error.h"
 17 #include "xfs_trace.h"
 18 #include "xfs_trans.h"
 19 #include "xfs_da_btree.h"
 20 #include "xfs_attr.h"
 21 #include "xfs_dir2.h"
 22 #include "xfs_dir2_priv.h"
 23 #include "xfs_attr_sf.h"
 24 #include "xfs_bmap.h"
 25 #include "xfs_defer.h"
 26 #include "xfs_log.h"
 27 #include "xfs_xattr.h"
 28 #include "xfs_parent.h"
 29 #include "xfs_trans_space.h"
 30 #include "xfs_attr_item.h"
 31 #include "xfs_health.h"
 32 
 33 struct kmem_cache               *xfs_parent_args_cache;
 34 
 35 /*
 36  * Parent pointer attribute handling.
 37  *
 38  * Because the attribute name is a filename component, it will never be longer
 39  * than 255 bytes and must not contain nulls or slashes.  These are roughly the
 40  * same constraints that apply to attribute names.
 41  *
 42  * The attribute value must always be a struct xfs_parent_rec.  This means the
 43  * attribute will never be in remote format because 12 bytes is nowhere near
 44  * xfs_attr_leaf_entsize_local_max() (~75% of block size).
 45  *
 46  * Creating a new parent attribute will always create a new attribute - there
 47  * should never, ever be an existing attribute in the tree for a new inode.
 48  * ENOSPC behavior is problematic - creating the inode without the parent
 49  * pointer is effectively a corruption, so we allow parent attribute creation
 50  * to dip into the reserve block pool to avoid unexpected ENOSPC errors from
 51  * occurring.
 52  */
 53 
 54 /* Return true if parent pointer attr name is valid. */
 55 bool
 56 xfs_parent_namecheck(
 57         unsigned int                    attr_flags,
 58         const void                      *name,
 59         size_t                          length)
 60 {
 61         /*
 62          * Parent pointers always use logged operations, so there should never
 63          * be incomplete xattrs.
 64          */
 65         if (attr_flags & XFS_ATTR_INCOMPLETE)
 66                 return false;
 67 
 68         return xfs_dir2_namecheck(name, length);
 69 }
 70 
 71 /* Return true if parent pointer attr value is valid. */
 72 bool
 73 xfs_parent_valuecheck(
 74         struct xfs_mount                *mp,
 75         const void                      *value,
 76         size_t                          valuelen)
 77 {
 78         const struct xfs_parent_rec     *rec = value;
 79 
 80         if (!xfs_has_parent(mp))
 81                 return false;
 82 
 83         /* The xattr value must be a parent record. */
 84         if (valuelen != sizeof(struct xfs_parent_rec))
 85                 return false;
 86 
 87         /* The parent record must be local. */
 88         if (value == NULL)
 89                 return false;
 90 
 91         /* The parent inumber must be valid. */
 92         if (!xfs_verify_dir_ino(mp, be64_to_cpu(rec->p_ino)))
 93                 return false;
 94 
 95         return true;
 96 }
 97 
 98 /* Compute the attribute name hash for a parent pointer. */
 99 xfs_dahash_t
100 xfs_parent_hashval(
101         struct xfs_mount                *mp,
102         const uint8_t                   *name,
103         int                             namelen,
104         xfs_ino_t                       parent_ino)
105 {
106         struct xfs_name                 xname = {
107                 .name                   = name,
108                 .len                    = namelen,
109         };
110 
111         /*
112          * Use the same dirent name hash as would be used on the directory, but
113          * mix in the parent inode number to avoid collisions on hardlinked
114          * files with identical names but different parents.
115          */
116         return xfs_dir2_hashname(mp, &xname) ^
117                 upper_32_bits(parent_ino) ^ lower_32_bits(parent_ino);
118 }
119 
120 /* Compute the attribute name hash from the xattr components. */
121 xfs_dahash_t
122 xfs_parent_hashattr(
123         struct xfs_mount                *mp,
124         const uint8_t                   *name,
125         int                             namelen,
126         const void                      *value,
127         int                             valuelen)
128 {
129         const struct xfs_parent_rec     *rec = value;
130 
131         /* Requires a local attr value in xfs_parent_rec format */
132         if (valuelen != sizeof(struct xfs_parent_rec)) {
133                 ASSERT(valuelen == sizeof(struct xfs_parent_rec));
134                 return 0;
135         }
136 
137         if (!value) {
138                 ASSERT(value != NULL);
139                 return 0;
140         }
141 
142         return xfs_parent_hashval(mp, name, namelen, be64_to_cpu(rec->p_ino));
143 }
144 
145 /*
146  * Initialize the parent pointer arguments structure.  Caller must have zeroed
147  * the contents of @args.  @tp is only required for updates.
148  */
149 static void
150 xfs_parent_da_args_init(
151         struct xfs_da_args      *args,
152         struct xfs_trans        *tp,
153         struct xfs_parent_rec   *rec,
154         struct xfs_inode        *child,
155         xfs_ino_t               owner,
156         const struct xfs_name   *parent_name)
157 {
158         args->geo = child->i_mount->m_attr_geo;
159         args->whichfork = XFS_ATTR_FORK;
160         args->attr_filter = XFS_ATTR_PARENT;
161         args->op_flags = XFS_DA_OP_LOGGED | XFS_DA_OP_OKNOENT;
162         args->trans = tp;
163         args->dp = child;
164         args->owner = owner;
165         args->name = parent_name->name;
166         args->namelen = parent_name->len;
167         args->value = rec;
168         args->valuelen = sizeof(struct xfs_parent_rec);
169         xfs_attr_sethash(args);
170 }
171 
172 /* Make sure the incore state is ready for a parent pointer query/update. */
173 static inline int
174 xfs_parent_iread_extents(
175         struct xfs_trans        *tp,
176         struct xfs_inode        *child)
177 {
178         /* Parent pointers require that the attr fork must exist. */
179         if (XFS_IS_CORRUPT(child->i_mount, !xfs_inode_has_attr_fork(child))) {
180                 xfs_inode_mark_sick(child, XFS_SICK_INO_PARENT);
181                 return -EFSCORRUPTED;
182         }
183 
184         return xfs_iread_extents(tp, child, XFS_ATTR_FORK);
185 }
186 
187 /* Add a parent pointer to reflect a dirent addition. */
188 int
189 xfs_parent_addname(
190         struct xfs_trans        *tp,
191         struct xfs_parent_args  *ppargs,
192         struct xfs_inode        *dp,
193         const struct xfs_name   *parent_name,
194         struct xfs_inode        *child)
195 {
196         int                     error;
197 
198         error = xfs_parent_iread_extents(tp, child);
199         if (error)
200                 return error;
201 
202         xfs_inode_to_parent_rec(&ppargs->rec, dp);
203         xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child,
204                         child->i_ino, parent_name);
205         xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_SET);
206         return 0;
207 }
208 
209 /* Remove a parent pointer to reflect a dirent removal. */
210 int
211 xfs_parent_removename(
212         struct xfs_trans        *tp,
213         struct xfs_parent_args  *ppargs,
214         struct xfs_inode        *dp,
215         const struct xfs_name   *parent_name,
216         struct xfs_inode        *child)
217 {
218         int                     error;
219 
220         error = xfs_parent_iread_extents(tp, child);
221         if (error)
222                 return error;
223 
224         xfs_inode_to_parent_rec(&ppargs->rec, dp);
225         xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child,
226                         child->i_ino, parent_name);
227         xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_REMOVE);
228         return 0;
229 }
230 
231 /* Replace one parent pointer with another to reflect a rename. */
232 int
233 xfs_parent_replacename(
234         struct xfs_trans        *tp,
235         struct xfs_parent_args  *ppargs,
236         struct xfs_inode        *old_dp,
237         const struct xfs_name   *old_name,
238         struct xfs_inode        *new_dp,
239         const struct xfs_name   *new_name,
240         struct xfs_inode        *child)
241 {
242         int                     error;
243 
244         error = xfs_parent_iread_extents(tp, child);
245         if (error)
246                 return error;
247 
248         xfs_inode_to_parent_rec(&ppargs->rec, old_dp);
249         xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child,
250                         child->i_ino, old_name);
251 
252         xfs_inode_to_parent_rec(&ppargs->new_rec, new_dp);
253         ppargs->args.new_name = new_name->name;
254         ppargs->args.new_namelen = new_name->len;
255         ppargs->args.new_value = &ppargs->new_rec;
256         ppargs->args.new_valuelen = sizeof(struct xfs_parent_rec);
257         xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_REPLACE);
258         return 0;
259 }
260 
261 /*
262  * Extract parent pointer information from any parent pointer xattr into
263  * @parent_ino/gen.  The last two parameters can be NULL pointers.
264  *
265  * Returns 0 if this is not a parent pointer xattr at all; or -EFSCORRUPTED for
266  * garbage.
267  */
268 int
269 xfs_parent_from_attr(
270         struct xfs_mount        *mp,
271         unsigned int            attr_flags,
272         const unsigned char     *name,
273         unsigned int            namelen,
274         const void              *value,
275         unsigned int            valuelen,
276         xfs_ino_t               *parent_ino,
277         uint32_t                *parent_gen)
278 {
279         const struct xfs_parent_rec     *rec = value;
280 
281         ASSERT(attr_flags & XFS_ATTR_PARENT);
282 
283         if (!xfs_parent_namecheck(attr_flags, name, namelen))
284                 return -EFSCORRUPTED;
285         if (!xfs_parent_valuecheck(mp, value, valuelen))
286                 return -EFSCORRUPTED;
287 
288         if (parent_ino)
289                 *parent_ino = be64_to_cpu(rec->p_ino);
290         if (parent_gen)
291                 *parent_gen = be32_to_cpu(rec->p_gen);
292         return 0;
293 }
294 
295 /*
296  * Look up a parent pointer record (@parent_name -> @pptr) of @ip.
297  *
298  * Caller must hold at least ILOCK_SHARED.  The scratchpad need not be
299  * initialized.
300  *
301  * Returns 0 if the pointer is found, -ENOATTR if there is no match, or a
302  * negative errno.
303  */
304 int
305 xfs_parent_lookup(
306         struct xfs_trans                *tp,
307         struct xfs_inode                *ip,
308         const struct xfs_name           *parent_name,
309         struct xfs_parent_rec           *pptr,
310         struct xfs_da_args              *scratch)
311 {
312         memset(scratch, 0, sizeof(struct xfs_da_args));
313         xfs_parent_da_args_init(scratch, tp, pptr, ip, ip->i_ino, parent_name);
314         return xfs_attr_get_ilocked(scratch);
315 }
316 
317 /* Sanity-check a parent pointer before we try to perform repairs. */
318 static inline bool
319 xfs_parent_sanity_check(
320         struct xfs_mount                *mp,
321         const struct xfs_name           *parent_name,
322         const struct xfs_parent_rec     *pptr)
323 {
324         if (!xfs_parent_namecheck(XFS_ATTR_PARENT, parent_name->name,
325                                 parent_name->len))
326                 return false;
327 
328         if (!xfs_parent_valuecheck(mp, pptr, sizeof(*pptr)))
329                 return false;
330 
331         return true;
332 }
333 
334 
335 /*
336  * Attach the parent pointer (@parent_name -> @pptr) to @ip immediately.
337  * Caller must not have a transaction or hold the ILOCK.  This is for
338  * specialized repair functions only.  The scratchpad need not be initialized.
339  */
340 int
341 xfs_parent_set(
342         struct xfs_inode        *ip,
343         xfs_ino_t               owner,
344         const struct xfs_name   *parent_name,
345         struct xfs_parent_rec   *pptr,
346         struct xfs_da_args      *scratch)
347 {
348         if (!xfs_parent_sanity_check(ip->i_mount, parent_name, pptr)) {
349                 ASSERT(0);
350                 return -EFSCORRUPTED;
351         }
352 
353         memset(scratch, 0, sizeof(struct xfs_da_args));
354         xfs_parent_da_args_init(scratch, NULL, pptr, ip, owner, parent_name);
355         return xfs_attr_set(scratch, XFS_ATTRUPDATE_CREATE, false);
356 }
357 
358 /*
359  * Remove the parent pointer (@parent_name -> @pptr) from @ip immediately.
360  * Caller must not have a transaction or hold the ILOCK.  This is for
361  * specialized repair functions only.  The scratchpad need not be initialized.
362  */
363 int
364 xfs_parent_unset(
365         struct xfs_inode                *ip,
366         xfs_ino_t                       owner,
367         const struct xfs_name           *parent_name,
368         struct xfs_parent_rec           *pptr,
369         struct xfs_da_args              *scratch)
370 {
371         if (!xfs_parent_sanity_check(ip->i_mount, parent_name, pptr)) {
372                 ASSERT(0);
373                 return -EFSCORRUPTED;
374         }
375 
376         memset(scratch, 0, sizeof(struct xfs_da_args));
377         xfs_parent_da_args_init(scratch, NULL, pptr, ip, owner, parent_name);
378         return xfs_attr_set(scratch, XFS_ATTRUPDATE_REMOVE, false);
379 }
380 

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

kernel.org | git.kernel.org | LWN.net | Project Home | 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.

sflogo.php