From: Darrick J. Wong <djwong@xxxxxxxxxx> Delete xattrs that have ATTR_PARENT set but are so garbage that they clearly aren't parent pointers. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- repair/pptr.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 2 deletions(-) diff --git a/repair/pptr.c b/repair/pptr.c index 11aa8d4e322..21b15ab80ea 100644 --- a/repair/pptr.c +++ b/repair/pptr.c @@ -192,6 +192,29 @@ struct file_scan { /* Does this file have garbage xattrs with ATTR_PARENT set? */ bool have_garbage; + + /* xattrs that we have to remove from this file */ + struct xfs_slab *garbage_xattr_recs; + + /* attr names associated with garbage_xattr_recs */ + struct xfblob *garbage_xattr_names; +}; + +struct garbage_xattr { + /* xfs_da_args.attr_filter for the attribute being removed */ + unsigned int attr_filter; + + /* attribute name length */ + unsigned int attrnamelen; + + /* attribute value length */ + unsigned int attrvaluelen; + + /* cookie for the attribute name */ + xfblob_cookie attrname_cookie; + + /* cookie for the attribute value */ + xfblob_cookie attrvalue_cookie; }; /* Global names storage file. */ @@ -381,6 +404,78 @@ add_parent_ptr( (unsigned long long)ag_pptr.name_cookie); } +/* Remove garbage extended attributes that have ATTR_PARENT set. */ +static void +remove_garbage_xattrs( + struct xfs_inode *ip, + struct file_scan *fscan) +{ + struct xfs_slab_cursor *cur; + struct garbage_xattr *ga; + void *buf = NULL; + size_t bufsize = 0; + int error; + + error = -init_slab_cursor(fscan->garbage_xattr_recs, NULL, &cur); + if (error) + do_error(_("init garbage xattr cursor failed: %s\n"), + strerror(error)); + + while ((ga = pop_slab_cursor(cur)) != NULL) { + struct xfs_da_args args = { + .dp = ip, + .attr_filter = ga->attr_filter, + .namelen = ga->attrnamelen, + .valuelen = ga->attrvaluelen, + .op_flags = XFS_DA_OP_REMOVE | XFS_DA_OP_NVLOOKUP, + }; + size_t desired = ga->attrnamelen + ga->attrvaluelen; + + if (desired > bufsize) { + free(buf); + buf = malloc(desired); + if (!buf) + do_error( + _("allocating %zu bytes to remove ino %llu garbage xattr failed: %s\n"), + desired, + (unsigned long long)ip->i_ino, + strerror(errno)); + bufsize = desired; + } + + args.name = buf; + args.value = buf + ga->attrnamelen; + + error = -xfblob_load(fscan->garbage_xattr_names, + ga->attrname_cookie, buf, ga->attrnamelen); + if (error) + do_error( + _("loading garbage xattr name failed: %s\n"), + strerror(error)); + + error = -xfblob_load(fscan->garbage_xattr_names, + ga->attrvalue_cookie, args.value, + ga->attrvaluelen); + if (error) + do_error( + _("loading garbage xattr value failed: %s\n"), + strerror(error)); + + error = -libxfs_attr_set(&args); + if (error) + do_error( + _("removing ino %llu garbage xattr failed: %s\n"), + (unsigned long long)ip->i_ino, + strerror(error)); + } + + free(buf); + free_slab_cursor(&cur); + free_slab(&fscan->garbage_xattr_recs); + xfblob_destroy(fscan->garbage_xattr_names); + fscan->garbage_xattr_names = NULL; +} + /* Schedule this ATTR_PARENT extended attribute for deletion. */ static void record_garbage_xattr( @@ -392,6 +487,15 @@ record_garbage_xattr( const void *value, unsigned int valuelen) { + struct garbage_xattr garbage_xattr = { + .attr_filter = attr_filter, + .attrnamelen = namelen, + .attrvaluelen = valuelen, + }; + struct xfs_mount *mp = ip->i_mount; + char *descr; + int error; + if (no_modify) { if (!fscan->have_garbage) do_warn( @@ -402,13 +506,47 @@ record_garbage_xattr( } if (fscan->have_garbage) - return; + goto stuffit; fscan->have_garbage = true; do_warn( _("deleting garbage parent pointer extended attributes in ino %llu\n"), (unsigned long long)ip->i_ino); - /* XXX do the work */ + + error = -init_slab(&fscan->garbage_xattr_recs, + sizeof(struct garbage_xattr)); + if (error) + do_error(_("init garbage xattr recs failed: %s\n"), + strerror(error)); + + descr = kasprintf("xfs_repair (%s): garbage xattr names", + mp->m_fsname); + error = -xfblob_create(descr, &fscan->garbage_xattr_names); + kfree(descr); + if (error) + do_error("init garbage xattr names failed: %s\n", + strerror(error)); + +stuffit: + error = -xfblob_store(fscan->garbage_xattr_names, + &garbage_xattr.attrname_cookie, name, namelen); + if (error) + do_error(_("storing ino %llu garbage xattr failed: %s\n"), + (unsigned long long)ip->i_ino, + strerror(error)); + + error = -xfblob_store(fscan->garbage_xattr_names, + &garbage_xattr.attrvalue_cookie, value, valuelen); + if (error) + do_error(_("storing ino %llu garbage xattr failed: %s\n"), + (unsigned long long)ip->i_ino, + strerror(error)); + + error = -slab_add(fscan->garbage_xattr_recs, &garbage_xattr); + if (error) + do_error(_("storing ino %llu garbage xattr rec failed: %s\n"), + (unsigned long long)ip->i_ino, + strerror(error)); } /* @@ -931,6 +1069,9 @@ check_file_parent_ptrs( goto out_free; } + if (!no_modify && fscan->have_garbage) + remove_garbage_xattrs(ip, fscan); + crosscheck_file_parent_ptrs(ip, fscan); out_free: