Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0 2 : /* 3 : * Copyright (c) 2022-2023 Oracle, Inc. 4 : * All rights reserved. 5 : */ 6 : #include "xfs.h" 7 : #include "xfs_fs.h" 8 : #include "xfs_format.h" 9 : #include "xfs_log_format.h" 10 : #include "xfs_shared.h" 11 : #include "xfs_trans_resv.h" 12 : #include "xfs_mount.h" 13 : #include "xfs_bmap_btree.h" 14 : #include "xfs_inode.h" 15 : #include "xfs_error.h" 16 : #include "xfs_trace.h" 17 : #include "xfs_trans.h" 18 : #include "xfs_da_format.h" 19 : #include "xfs_da_btree.h" 20 : #include "xfs_attr.h" 21 : #include "xfs_ioctl.h" 22 : #include "xfs_parent.h" 23 : #include "xfs_da_btree.h" 24 : #include "xfs_parent_utils.h" 25 : #include "xfs_health.h" 26 : 27 : struct xfs_getparent_ctx { 28 : struct xfs_attr_list_context context; 29 : struct xfs_parent_name_irec pptr_irec; 30 : struct xfs_getparents *ppi; 31 : }; 32 : 33 : static inline unsigned int 34 : xfs_getparents_rec_sizeof( 35 : const struct xfs_parent_name_irec *irec) 36 : { 37 215608261 : return round_up(sizeof(struct xfs_getparents_rec) + irec->p_namelen + 1, 38 : sizeof(uint32_t)); 39 : } 40 : 41 : static void 42 4610875373 : xfs_getparent_listent( 43 : struct xfs_attr_list_context *context, 44 : int flags, 45 : unsigned char *name, 46 : int namelen, 47 : void *value, 48 : int valuelen) 49 : { 50 4610875373 : struct xfs_getparent_ctx *gp; 51 4610875373 : struct xfs_getparents *ppi; 52 4610875373 : struct xfs_getparents_rec *pptr; 53 4610875373 : struct xfs_parent_name_rec *rec = (void *)name; 54 4610875373 : struct xfs_parent_name_irec *irec; 55 4610875373 : struct xfs_mount *mp = context->dp->i_mount; 56 4610875373 : int arraytop; 57 : 58 4610875373 : gp = container_of(context, struct xfs_getparent_ctx, context); 59 4610875373 : ppi = gp->ppi; 60 4610875373 : irec = &gp->pptr_irec; 61 : 62 : /* Ignore non-parent xattrs */ 63 4610875373 : if (!(flags & XFS_ATTR_PARENT)) 64 : return; 65 : 66 : /* 67 : * Report corruption for anything that doesn't look like a parent 68 : * pointer. The attr list functions filtered out INCOMPLETE attrs. 69 : */ 70 215672933 : if (XFS_IS_CORRUPT(mp, 71 : !xfs_parent_namecheck(mp, rec, namelen, flags)) || 72 215680383 : XFS_IS_CORRUPT(mp, 73 : !xfs_parent_valuecheck(mp, value, valuelen))) { 74 0 : xfs_inode_mark_sick(context->dp, XFS_SICK_INO_PARENT); 75 0 : context->seen_enough = -EFSCORRUPTED; 76 0 : return; 77 : } 78 : 79 215644133 : xfs_parent_irec_from_disk(&gp->pptr_irec, rec, value, valuelen); 80 : 81 : /* 82 : * We found a parent pointer, but we've filled up the buffer. Signal 83 : * to the caller that we did /not/ reach the end of the parent pointer 84 : * recordset. 85 : */ 86 215608261 : arraytop = xfs_getparents_arraytop(ppi, ppi->gp_count + 1); 87 215608261 : context->firstu -= xfs_getparents_rec_sizeof(irec); 88 215608261 : if (context->firstu < arraytop) { 89 66 : context->seen_enough = 1; 90 66 : return; 91 : } 92 : 93 215608195 : trace_xfs_getparent_listent(context->dp, ppi, irec); 94 : 95 : /* Format the parent pointer directly into the caller buffer. */ 96 215618156 : ppi->gp_offsets[ppi->gp_count] = context->firstu; 97 215618156 : pptr = xfs_getparents_rec(ppi, ppi->gp_count); 98 215618156 : pptr->gpr_ino = irec->p_ino; 99 215618156 : pptr->gpr_gen = irec->p_gen; 100 215618156 : pptr->gpr_pad = 0; 101 215618156 : pptr->gpr_rsvd = 0; 102 : 103 431236312 : memcpy(pptr->gpr_name, irec->p_name, irec->p_namelen); 104 215618156 : pptr->gpr_name[irec->p_namelen] = 0; 105 215618156 : ppi->gp_count++; 106 : } 107 : 108 : /* Retrieve the parent pointers for a given inode. */ 109 : int 110 258603175 : xfs_getparent_pointers( 111 : struct xfs_inode *ip, 112 : struct xfs_getparents *ppi) 113 : { 114 258603175 : struct xfs_getparent_ctx *gp; 115 258603175 : int error; 116 : 117 258603175 : gp = kzalloc(sizeof(struct xfs_getparent_ctx), GFP_KERNEL); 118 258595182 : if (!gp) 119 : return -ENOMEM; 120 258595182 : gp->ppi = ppi; 121 258595182 : gp->context.dp = ip; 122 258595182 : gp->context.resynch = 1; 123 258595182 : gp->context.put_listent = xfs_getparent_listent; 124 258595182 : gp->context.bufsize = round_down(ppi->gp_bufsize, sizeof(uint32_t)); 125 258595182 : gp->context.firstu = gp->context.bufsize; 126 : 127 : /* Copy the cursor provided by caller */ 128 517190364 : memcpy(&gp->context.cursor, &ppi->gp_cursor, 129 : sizeof(struct xfs_attrlist_cursor)); 130 258595182 : ppi->gp_count = 0; 131 : 132 258595182 : trace_xfs_getparent_pointers(ip, ppi, &gp->context.cursor); 133 : 134 258583191 : error = xfs_attr_list(&gp->context); 135 258520660 : if (error) 136 0 : goto out_free; 137 258520660 : if (gp->context.seen_enough < 0) { 138 0 : error = gp->context.seen_enough; 139 0 : goto out_free; 140 : } 141 : 142 : /* Is this the root directory? */ 143 258520660 : if (ip->i_ino == ip->i_mount->m_sb.sb_rootino) 144 43850257 : ppi->gp_flags |= XFS_GETPARENTS_OFLAG_ROOT; 145 : 146 : /* 147 : * If we did not run out of buffer space, then we reached the end of 148 : * the pptr recordset, so set the DONE flag. 149 : */ 150 258520660 : if (gp->context.seen_enough == 0) 151 258523495 : ppi->gp_flags |= XFS_GETPARENTS_OFLAG_DONE; 152 : 153 : /* Update the caller with the current cursor position */ 154 517041320 : memcpy(&ppi->gp_cursor, &gp->context.cursor, 155 : sizeof(struct xfs_attrlist_cursor)); 156 258520660 : out_free: 157 258520660 : kfree(gp); 158 258520660 : return error; 159 : }