If the filesystem has ea_inode set, then each file that has xattrs might
have stored an xattr value in a separate inode. These inodes also need
to be freed, so create a library function to do that, and call it from
the fuse2fs unlink method. Seen by ext4/026.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Link: https://lore.kernel.org/r/174786677996.1383760.7408606469648643965.stgit@frogsfrogsfrogs
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
ext2fs_xattr_get@Base 1.43
ext2fs_xattr_inode_max_size@Base 1.43
ext2fs_xattr_remove@Base 1.43
+ ext2fs_xattr_remove_all@Base 1.47.3
ext2fs_xattr_set@Base 1.43
ext2fs_xattrs_close@Base 1.43
ext2fs_xattrs_count@Base 1.43
size_t value_len);
errcode_t ext2fs_xattr_remove(struct ext2_xattr_handle *handle,
const char *key);
+errcode_t ext2fs_xattr_remove_all(struct ext2_xattr_handle *handle);
errcode_t ext2fs_xattrs_open(ext2_filsys fs, ext2_ino_t ino,
struct ext2_xattr_handle **handle);
errcode_t ext2fs_xattrs_close(struct ext2_xattr_handle **handle);
goto out;
}
+ inode.i_flags &= ~EXT4_EA_INODE_FL;
ext2fs_inode_alloc_stats2(fs, ino, -1 /* inuse */, 0 /* is_dir */);
write_out:
return 0;
}
+errcode_t ext2fs_xattr_remove_all(struct ext2_xattr_handle *handle)
+{
+ struct ext2_xattr *x;
+ struct ext2_xattr *end = handle->attrs + handle->count;
+
+ EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
+ for (x = handle->attrs; x < end; x++) {
+ ext2fs_free_mem(&x->name);
+ ext2fs_free_mem(&x->value);
+ if (x->ea_ino)
+ xattr_inode_dec_ref(handle->fs, x->ea_ino);
+ }
+
+ handle->ibody_count = 0;
+ handle->count = 0;
+ return ext2fs_xattrs_write(handle);
+}
+
errcode_t ext2fs_xattrs_open(ext2_filsys fs, ext2_ino_t ino,
struct ext2_xattr_handle **handle)
{
return update_mtime(fs, dir, NULL);
}
+static errcode_t remove_ea_inodes(struct fuse2fs *ff, ext2_ino_t ino,
+ struct ext2_inode_large *inode)
+{
+ ext2_filsys fs = ff->fs;
+ struct ext2_xattr_handle *h;
+ errcode_t err;
+
+ /*
+ * The xattr handle maintains its own private copy of the inode, so
+ * write ours to disk so that we can read it.
+ */
+ err = fuse2fs_write_inode(fs, ino, inode);
+ if (err)
+ return err;
+
+ err = ext2fs_xattrs_open(fs, ino, &h);
+ if (err)
+ return err;
+
+ err = ext2fs_xattrs_read(h);
+ if (err)
+ goto out_close;
+
+ err = ext2fs_xattr_remove_all(h);
+ if (err)
+ goto out_close;
+
+out_close:
+ ext2fs_xattrs_close(&h);
+
+ /* Now read the inode back in. */
+ return fuse2fs_read_inode(fs, ino, inode);
+}
+
static int remove_inode(struct fuse2fs *ff, ext2_ino_t ino)
{
ext2_filsys fs = ff->fs;
if (inode.i_links_count)
goto write_out;
+ if (ext2fs_has_feature_ea_inode(fs->super)) {
+ err = remove_ea_inodes(ff, ino, &inode);
+ if (err)
+ goto write_out;
+ }
+
/* Nobody holds this file; free its blocks! */
err = ext2fs_free_ext_attr(fs, ino, &inode);
if (err)