162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/reiserfs/xattr.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2002 by Jeff Mahoney, <jeffm@suse.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci/* 1062306a36Sopenharmony_ci * In order to implement EA/ACLs in a clean, backwards compatible manner, 1162306a36Sopenharmony_ci * they are implemented as files in a "private" directory. 1262306a36Sopenharmony_ci * Each EA is in it's own file, with the directory layout like so (/ is assumed 1362306a36Sopenharmony_ci * to be relative to fs root). Inside the /.reiserfs_priv/xattrs directory, 1462306a36Sopenharmony_ci * directories named using the capital-hex form of the objectid and 1562306a36Sopenharmony_ci * generation number are used. Inside each directory are individual files 1662306a36Sopenharmony_ci * named with the name of the extended attribute. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * So, for objectid 12648430, we could have: 1962306a36Sopenharmony_ci * /.reiserfs_priv/xattrs/C0FFEE.0/system.posix_acl_access 2062306a36Sopenharmony_ci * /.reiserfs_priv/xattrs/C0FFEE.0/system.posix_acl_default 2162306a36Sopenharmony_ci * /.reiserfs_priv/xattrs/C0FFEE.0/user.Content-Type 2262306a36Sopenharmony_ci * .. or similar. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * The file contents are the text of the EA. The size is known based on the 2562306a36Sopenharmony_ci * stat data describing the file. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * In the case of system.posix_acl_access and system.posix_acl_default, since 2862306a36Sopenharmony_ci * these are special cases for filesystem ACLs, they are interpreted by the 2962306a36Sopenharmony_ci * kernel, in addition, they are negatively and positively cached and attached 3062306a36Sopenharmony_ci * to the inode so that unnecessary lookups are avoided. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * Locking works like so: 3362306a36Sopenharmony_ci * Directory components (xattr root, xattr dir) are protectd by their i_mutex. 3462306a36Sopenharmony_ci * The xattrs themselves are protected by the xattr_sem. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include "reiserfs.h" 3862306a36Sopenharmony_ci#include <linux/capability.h> 3962306a36Sopenharmony_ci#include <linux/dcache.h> 4062306a36Sopenharmony_ci#include <linux/namei.h> 4162306a36Sopenharmony_ci#include <linux/errno.h> 4262306a36Sopenharmony_ci#include <linux/gfp.h> 4362306a36Sopenharmony_ci#include <linux/fs.h> 4462306a36Sopenharmony_ci#include <linux/file.h> 4562306a36Sopenharmony_ci#include <linux/pagemap.h> 4662306a36Sopenharmony_ci#include <linux/xattr.h> 4762306a36Sopenharmony_ci#include "xattr.h" 4862306a36Sopenharmony_ci#include "acl.h" 4962306a36Sopenharmony_ci#include <linux/uaccess.h> 5062306a36Sopenharmony_ci#include <net/checksum.h> 5162306a36Sopenharmony_ci#include <linux/stat.h> 5262306a36Sopenharmony_ci#include <linux/quotaops.h> 5362306a36Sopenharmony_ci#include <linux/security.h> 5462306a36Sopenharmony_ci#include <linux/posix_acl_xattr.h> 5562306a36Sopenharmony_ci#include <linux/xattr.h> 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define PRIVROOT_NAME ".reiserfs_priv" 5862306a36Sopenharmony_ci#define XAROOT_NAME "xattrs" 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * Helpers for inode ops. We do this so that we don't have all the VFS 6362306a36Sopenharmony_ci * overhead and also for proper i_mutex annotation. 6462306a36Sopenharmony_ci * dir->i_mutex must be held for all of them. 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_FS_XATTR 6762306a36Sopenharmony_cistatic int xattr_create(struct inode *dir, struct dentry *dentry, int mode) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci BUG_ON(!inode_is_locked(dir)); 7062306a36Sopenharmony_ci return dir->i_op->create(&nop_mnt_idmap, dir, dentry, mode, true); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci#endif 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int xattr_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci BUG_ON(!inode_is_locked(dir)); 7762306a36Sopenharmony_ci return dir->i_op->mkdir(&nop_mnt_idmap, dir, dentry, mode); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* 8162306a36Sopenharmony_ci * We use I_MUTEX_CHILD here to silence lockdep. It's safe because xattr 8262306a36Sopenharmony_ci * mutation ops aren't called during rename or splace, which are the 8362306a36Sopenharmony_ci * only other users of I_MUTEX_CHILD. It violates the ordering, but that's 8462306a36Sopenharmony_ci * better than allocating another subclass just for this code. 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_cistatic int xattr_unlink(struct inode *dir, struct dentry *dentry) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci int error; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci BUG_ON(!inode_is_locked(dir)); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci inode_lock_nested(d_inode(dentry), I_MUTEX_CHILD); 9362306a36Sopenharmony_ci error = dir->i_op->unlink(dir, dentry); 9462306a36Sopenharmony_ci inode_unlock(d_inode(dentry)); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (!error) 9762306a36Sopenharmony_ci d_delete(dentry); 9862306a36Sopenharmony_ci return error; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int xattr_rmdir(struct inode *dir, struct dentry *dentry) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci int error; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci BUG_ON(!inode_is_locked(dir)); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci inode_lock_nested(d_inode(dentry), I_MUTEX_CHILD); 10862306a36Sopenharmony_ci error = dir->i_op->rmdir(dir, dentry); 10962306a36Sopenharmony_ci if (!error) 11062306a36Sopenharmony_ci d_inode(dentry)->i_flags |= S_DEAD; 11162306a36Sopenharmony_ci inode_unlock(d_inode(dentry)); 11262306a36Sopenharmony_ci if (!error) 11362306a36Sopenharmony_ci d_delete(dentry); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return error; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci#define xattr_may_create(flags) (!flags || flags & XATTR_CREATE) 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic struct dentry *open_xa_root(struct super_block *sb, int flags) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct dentry *privroot = REISERFS_SB(sb)->priv_root; 12362306a36Sopenharmony_ci struct dentry *xaroot; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (d_really_is_negative(privroot)) 12662306a36Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci inode_lock_nested(d_inode(privroot), I_MUTEX_XATTR); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci xaroot = dget(REISERFS_SB(sb)->xattr_root); 13162306a36Sopenharmony_ci if (!xaroot) 13262306a36Sopenharmony_ci xaroot = ERR_PTR(-EOPNOTSUPP); 13362306a36Sopenharmony_ci else if (d_really_is_negative(xaroot)) { 13462306a36Sopenharmony_ci int err = -ENODATA; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (xattr_may_create(flags)) 13762306a36Sopenharmony_ci err = xattr_mkdir(d_inode(privroot), xaroot, 0700); 13862306a36Sopenharmony_ci if (err) { 13962306a36Sopenharmony_ci dput(xaroot); 14062306a36Sopenharmony_ci xaroot = ERR_PTR(err); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci inode_unlock(d_inode(privroot)); 14562306a36Sopenharmony_ci return xaroot; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic struct dentry *open_xa_dir(const struct inode *inode, int flags) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct dentry *xaroot, *xadir; 15162306a36Sopenharmony_ci char namebuf[17]; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci xaroot = open_xa_root(inode->i_sb, flags); 15462306a36Sopenharmony_ci if (IS_ERR(xaroot)) 15562306a36Sopenharmony_ci return xaroot; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci snprintf(namebuf, sizeof(namebuf), "%X.%X", 15862306a36Sopenharmony_ci le32_to_cpu(INODE_PKEY(inode)->k_objectid), 15962306a36Sopenharmony_ci inode->i_generation); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci inode_lock_nested(d_inode(xaroot), I_MUTEX_XATTR); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci xadir = lookup_one_len(namebuf, xaroot, strlen(namebuf)); 16462306a36Sopenharmony_ci if (!IS_ERR(xadir) && d_really_is_negative(xadir)) { 16562306a36Sopenharmony_ci int err = -ENODATA; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (xattr_may_create(flags)) 16862306a36Sopenharmony_ci err = xattr_mkdir(d_inode(xaroot), xadir, 0700); 16962306a36Sopenharmony_ci if (err) { 17062306a36Sopenharmony_ci dput(xadir); 17162306a36Sopenharmony_ci xadir = ERR_PTR(err); 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci inode_unlock(d_inode(xaroot)); 17662306a36Sopenharmony_ci dput(xaroot); 17762306a36Sopenharmony_ci return xadir; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci/* 18162306a36Sopenharmony_ci * The following are side effects of other operations that aren't explicitly 18262306a36Sopenharmony_ci * modifying extended attributes. This includes operations such as permissions 18362306a36Sopenharmony_ci * or ownership changes, object deletions, etc. 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_cistruct reiserfs_dentry_buf { 18662306a36Sopenharmony_ci struct dir_context ctx; 18762306a36Sopenharmony_ci struct dentry *xadir; 18862306a36Sopenharmony_ci int count; 18962306a36Sopenharmony_ci int err; 19062306a36Sopenharmony_ci struct dentry *dentries[8]; 19162306a36Sopenharmony_ci}; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic bool 19462306a36Sopenharmony_cifill_with_dentries(struct dir_context *ctx, const char *name, int namelen, 19562306a36Sopenharmony_ci loff_t offset, u64 ino, unsigned int d_type) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci struct reiserfs_dentry_buf *dbuf = 19862306a36Sopenharmony_ci container_of(ctx, struct reiserfs_dentry_buf, ctx); 19962306a36Sopenharmony_ci struct dentry *dentry; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci WARN_ON_ONCE(!inode_is_locked(d_inode(dbuf->xadir))); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (dbuf->count == ARRAY_SIZE(dbuf->dentries)) 20462306a36Sopenharmony_ci return false; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (name[0] == '.' && (namelen < 2 || 20762306a36Sopenharmony_ci (namelen == 2 && name[1] == '.'))) 20862306a36Sopenharmony_ci return true; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci dentry = lookup_one_len(name, dbuf->xadir, namelen); 21162306a36Sopenharmony_ci if (IS_ERR(dentry)) { 21262306a36Sopenharmony_ci dbuf->err = PTR_ERR(dentry); 21362306a36Sopenharmony_ci return false; 21462306a36Sopenharmony_ci } else if (d_really_is_negative(dentry)) { 21562306a36Sopenharmony_ci /* A directory entry exists, but no file? */ 21662306a36Sopenharmony_ci reiserfs_error(dentry->d_sb, "xattr-20003", 21762306a36Sopenharmony_ci "Corrupted directory: xattr %pd listed but " 21862306a36Sopenharmony_ci "not found for file %pd.\n", 21962306a36Sopenharmony_ci dentry, dbuf->xadir); 22062306a36Sopenharmony_ci dput(dentry); 22162306a36Sopenharmony_ci dbuf->err = -EIO; 22262306a36Sopenharmony_ci return false; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci dbuf->dentries[dbuf->count++] = dentry; 22662306a36Sopenharmony_ci return true; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic void 23062306a36Sopenharmony_cicleanup_dentry_buf(struct reiserfs_dentry_buf *buf) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci int i; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci for (i = 0; i < buf->count; i++) 23562306a36Sopenharmony_ci if (buf->dentries[i]) 23662306a36Sopenharmony_ci dput(buf->dentries[i]); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int reiserfs_for_each_xattr(struct inode *inode, 24062306a36Sopenharmony_ci int (*action)(struct dentry *, void *), 24162306a36Sopenharmony_ci void *data) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct dentry *dir; 24462306a36Sopenharmony_ci int i, err = 0; 24562306a36Sopenharmony_ci struct reiserfs_dentry_buf buf = { 24662306a36Sopenharmony_ci .ctx.actor = fill_with_dentries, 24762306a36Sopenharmony_ci }; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* Skip out, an xattr has no xattrs associated with it */ 25062306a36Sopenharmony_ci if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) 25162306a36Sopenharmony_ci return 0; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci dir = open_xa_dir(inode, XATTR_REPLACE); 25462306a36Sopenharmony_ci if (IS_ERR(dir)) { 25562306a36Sopenharmony_ci err = PTR_ERR(dir); 25662306a36Sopenharmony_ci goto out; 25762306a36Sopenharmony_ci } else if (d_really_is_negative(dir)) { 25862306a36Sopenharmony_ci err = 0; 25962306a36Sopenharmony_ci goto out_dir; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci inode_lock_nested(d_inode(dir), I_MUTEX_XATTR); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci buf.xadir = dir; 26562306a36Sopenharmony_ci while (1) { 26662306a36Sopenharmony_ci err = reiserfs_readdir_inode(d_inode(dir), &buf.ctx); 26762306a36Sopenharmony_ci if (err) 26862306a36Sopenharmony_ci break; 26962306a36Sopenharmony_ci if (buf.err) { 27062306a36Sopenharmony_ci err = buf.err; 27162306a36Sopenharmony_ci break; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci if (!buf.count) 27462306a36Sopenharmony_ci break; 27562306a36Sopenharmony_ci for (i = 0; !err && i < buf.count && buf.dentries[i]; i++) { 27662306a36Sopenharmony_ci struct dentry *dentry = buf.dentries[i]; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (!d_is_dir(dentry)) 27962306a36Sopenharmony_ci err = action(dentry, data); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci dput(dentry); 28262306a36Sopenharmony_ci buf.dentries[i] = NULL; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci if (err) 28562306a36Sopenharmony_ci break; 28662306a36Sopenharmony_ci buf.count = 0; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci inode_unlock(d_inode(dir)); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci cleanup_dentry_buf(&buf); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (!err) { 29362306a36Sopenharmony_ci /* 29462306a36Sopenharmony_ci * We start a transaction here to avoid a ABBA situation 29562306a36Sopenharmony_ci * between the xattr root's i_mutex and the journal lock. 29662306a36Sopenharmony_ci * This doesn't incur much additional overhead since the 29762306a36Sopenharmony_ci * new transaction will just nest inside the 29862306a36Sopenharmony_ci * outer transaction. 29962306a36Sopenharmony_ci */ 30062306a36Sopenharmony_ci int blocks = JOURNAL_PER_BALANCE_CNT * 2 + 2 + 30162306a36Sopenharmony_ci 4 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb); 30262306a36Sopenharmony_ci struct reiserfs_transaction_handle th; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci reiserfs_write_lock(inode->i_sb); 30562306a36Sopenharmony_ci err = journal_begin(&th, inode->i_sb, blocks); 30662306a36Sopenharmony_ci reiserfs_write_unlock(inode->i_sb); 30762306a36Sopenharmony_ci if (!err) { 30862306a36Sopenharmony_ci int jerror; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci inode_lock_nested(d_inode(dir->d_parent), 31162306a36Sopenharmony_ci I_MUTEX_XATTR); 31262306a36Sopenharmony_ci err = action(dir, data); 31362306a36Sopenharmony_ci reiserfs_write_lock(inode->i_sb); 31462306a36Sopenharmony_ci jerror = journal_end(&th); 31562306a36Sopenharmony_ci reiserfs_write_unlock(inode->i_sb); 31662306a36Sopenharmony_ci inode_unlock(d_inode(dir->d_parent)); 31762306a36Sopenharmony_ci err = jerror ?: err; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ciout_dir: 32162306a36Sopenharmony_ci dput(dir); 32262306a36Sopenharmony_ciout: 32362306a36Sopenharmony_ci /* 32462306a36Sopenharmony_ci * -ENODATA: this object doesn't have any xattrs 32562306a36Sopenharmony_ci * -EOPNOTSUPP: this file system doesn't have xattrs enabled on disk. 32662306a36Sopenharmony_ci * Neither are errors 32762306a36Sopenharmony_ci */ 32862306a36Sopenharmony_ci if (err == -ENODATA || err == -EOPNOTSUPP) 32962306a36Sopenharmony_ci err = 0; 33062306a36Sopenharmony_ci return err; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic int delete_one_xattr(struct dentry *dentry, void *data) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct inode *dir = d_inode(dentry->d_parent); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* This is the xattr dir, handle specially. */ 33862306a36Sopenharmony_ci if (d_is_dir(dentry)) 33962306a36Sopenharmony_ci return xattr_rmdir(dir, dentry); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci return xattr_unlink(dir, dentry); 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic int chown_one_xattr(struct dentry *dentry, void *data) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci struct iattr *attrs = data; 34762306a36Sopenharmony_ci int ia_valid = attrs->ia_valid; 34862306a36Sopenharmony_ci int err; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* 35162306a36Sopenharmony_ci * We only want the ownership bits. Otherwise, we'll do 35262306a36Sopenharmony_ci * things like change a directory to a regular file if 35362306a36Sopenharmony_ci * ATTR_MODE is set. 35462306a36Sopenharmony_ci */ 35562306a36Sopenharmony_ci attrs->ia_valid &= (ATTR_UID|ATTR_GID); 35662306a36Sopenharmony_ci err = reiserfs_setattr(&nop_mnt_idmap, dentry, attrs); 35762306a36Sopenharmony_ci attrs->ia_valid = ia_valid; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci return err; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci/* No i_mutex, but the inode is unconnected. */ 36362306a36Sopenharmony_ciint reiserfs_delete_xattrs(struct inode *inode) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci int err = reiserfs_for_each_xattr(inode, delete_one_xattr, NULL); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (err) 36862306a36Sopenharmony_ci reiserfs_warning(inode->i_sb, "jdm-20004", 36962306a36Sopenharmony_ci "Couldn't delete all xattrs (%d)\n", err); 37062306a36Sopenharmony_ci return err; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci/* inode->i_mutex: down */ 37462306a36Sopenharmony_ciint reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci int err = reiserfs_for_each_xattr(inode, chown_one_xattr, attrs); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (err) 37962306a36Sopenharmony_ci reiserfs_warning(inode->i_sb, "jdm-20007", 38062306a36Sopenharmony_ci "Couldn't chown all xattrs (%d)\n", err); 38162306a36Sopenharmony_ci return err; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_FS_XATTR 38562306a36Sopenharmony_ci/* 38662306a36Sopenharmony_ci * Returns a dentry corresponding to a specific extended attribute file 38762306a36Sopenharmony_ci * for the inode. If flags allow, the file is created. Otherwise, a 38862306a36Sopenharmony_ci * valid or negative dentry, or an error is returned. 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_cistatic struct dentry *xattr_lookup(struct inode *inode, const char *name, 39162306a36Sopenharmony_ci int flags) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci struct dentry *xadir, *xafile; 39462306a36Sopenharmony_ci int err = 0; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci xadir = open_xa_dir(inode, flags); 39762306a36Sopenharmony_ci if (IS_ERR(xadir)) 39862306a36Sopenharmony_ci return ERR_CAST(xadir); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci inode_lock_nested(d_inode(xadir), I_MUTEX_XATTR); 40162306a36Sopenharmony_ci xafile = lookup_one_len(name, xadir, strlen(name)); 40262306a36Sopenharmony_ci if (IS_ERR(xafile)) { 40362306a36Sopenharmony_ci err = PTR_ERR(xafile); 40462306a36Sopenharmony_ci goto out; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (d_really_is_positive(xafile) && (flags & XATTR_CREATE)) 40862306a36Sopenharmony_ci err = -EEXIST; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci if (d_really_is_negative(xafile)) { 41162306a36Sopenharmony_ci err = -ENODATA; 41262306a36Sopenharmony_ci if (xattr_may_create(flags)) 41362306a36Sopenharmony_ci err = xattr_create(d_inode(xadir), xafile, 41462306a36Sopenharmony_ci 0700|S_IFREG); 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if (err) 41862306a36Sopenharmony_ci dput(xafile); 41962306a36Sopenharmony_ciout: 42062306a36Sopenharmony_ci inode_unlock(d_inode(xadir)); 42162306a36Sopenharmony_ci dput(xadir); 42262306a36Sopenharmony_ci if (err) 42362306a36Sopenharmony_ci return ERR_PTR(err); 42462306a36Sopenharmony_ci return xafile; 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci/* Internal operations on file data */ 42862306a36Sopenharmony_cistatic inline void reiserfs_put_page(struct page *page) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci kunmap(page); 43162306a36Sopenharmony_ci put_page(page); 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic struct page *reiserfs_get_page(struct inode *dir, size_t n) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci struct address_space *mapping = dir->i_mapping; 43762306a36Sopenharmony_ci struct page *page; 43862306a36Sopenharmony_ci /* 43962306a36Sopenharmony_ci * We can deadlock if we try to free dentries, 44062306a36Sopenharmony_ci * and an unlink/rmdir has just occurred - GFP_NOFS avoids this 44162306a36Sopenharmony_ci */ 44262306a36Sopenharmony_ci mapping_set_gfp_mask(mapping, GFP_NOFS); 44362306a36Sopenharmony_ci page = read_mapping_page(mapping, n >> PAGE_SHIFT, NULL); 44462306a36Sopenharmony_ci if (!IS_ERR(page)) 44562306a36Sopenharmony_ci kmap(page); 44662306a36Sopenharmony_ci return page; 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic inline __u32 xattr_hash(const char *msg, int len) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci /* 45262306a36Sopenharmony_ci * csum_partial() gives different results for little-endian and 45362306a36Sopenharmony_ci * big endian hosts. Images created on little-endian hosts and 45462306a36Sopenharmony_ci * mounted on big-endian hosts(and vice versa) will see csum mismatches 45562306a36Sopenharmony_ci * when trying to fetch xattrs. Treating the hash as __wsum_t would 45662306a36Sopenharmony_ci * lower the frequency of mismatch. This is an endianness bug in 45762306a36Sopenharmony_ci * reiserfs. The return statement would result in a sparse warning. Do 45862306a36Sopenharmony_ci * not fix the sparse warning so as to not hide a reminder of the bug. 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_ci return csum_partial(msg, len, 0); 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ciint reiserfs_commit_write(struct file *f, struct page *page, 46462306a36Sopenharmony_ci unsigned from, unsigned to); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic void update_ctime(struct inode *inode) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct timespec64 now = current_time(inode); 46962306a36Sopenharmony_ci struct timespec64 ctime = inode_get_ctime(inode); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (inode_unhashed(inode) || !inode->i_nlink || 47262306a36Sopenharmony_ci timespec64_equal(&ctime, &now)) 47362306a36Sopenharmony_ci return; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci inode_set_ctime_to_ts(inode, now); 47662306a36Sopenharmony_ci mark_inode_dirty(inode); 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic int lookup_and_delete_xattr(struct inode *inode, const char *name) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci int err = 0; 48262306a36Sopenharmony_ci struct dentry *dentry, *xadir; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci xadir = open_xa_dir(inode, XATTR_REPLACE); 48562306a36Sopenharmony_ci if (IS_ERR(xadir)) 48662306a36Sopenharmony_ci return PTR_ERR(xadir); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci inode_lock_nested(d_inode(xadir), I_MUTEX_XATTR); 48962306a36Sopenharmony_ci dentry = lookup_one_len(name, xadir, strlen(name)); 49062306a36Sopenharmony_ci if (IS_ERR(dentry)) { 49162306a36Sopenharmony_ci err = PTR_ERR(dentry); 49262306a36Sopenharmony_ci goto out_dput; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (d_really_is_positive(dentry)) { 49662306a36Sopenharmony_ci err = xattr_unlink(d_inode(xadir), dentry); 49762306a36Sopenharmony_ci update_ctime(inode); 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci dput(dentry); 50162306a36Sopenharmony_ciout_dput: 50262306a36Sopenharmony_ci inode_unlock(d_inode(xadir)); 50362306a36Sopenharmony_ci dput(xadir); 50462306a36Sopenharmony_ci return err; 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci/* Generic extended attribute operations that can be used by xa plugins */ 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci/* 51162306a36Sopenharmony_ci * inode->i_mutex: down 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_ciint 51462306a36Sopenharmony_cireiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th, 51562306a36Sopenharmony_ci struct inode *inode, const char *name, 51662306a36Sopenharmony_ci const void *buffer, size_t buffer_size, int flags) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci int err = 0; 51962306a36Sopenharmony_ci struct dentry *dentry; 52062306a36Sopenharmony_ci struct page *page; 52162306a36Sopenharmony_ci char *data; 52262306a36Sopenharmony_ci size_t file_pos = 0; 52362306a36Sopenharmony_ci size_t buffer_pos = 0; 52462306a36Sopenharmony_ci size_t new_size; 52562306a36Sopenharmony_ci __u32 xahash = 0; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if (get_inode_sd_version(inode) == STAT_DATA_V1) 52862306a36Sopenharmony_ci return -EOPNOTSUPP; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci if (!buffer) { 53162306a36Sopenharmony_ci err = lookup_and_delete_xattr(inode, name); 53262306a36Sopenharmony_ci return err; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci dentry = xattr_lookup(inode, name, flags); 53662306a36Sopenharmony_ci if (IS_ERR(dentry)) 53762306a36Sopenharmony_ci return PTR_ERR(dentry); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci down_write(&REISERFS_I(inode)->i_xattr_sem); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci xahash = xattr_hash(buffer, buffer_size); 54262306a36Sopenharmony_ci while (buffer_pos < buffer_size || buffer_pos == 0) { 54362306a36Sopenharmony_ci size_t chunk; 54462306a36Sopenharmony_ci size_t skip = 0; 54562306a36Sopenharmony_ci size_t page_offset = (file_pos & (PAGE_SIZE - 1)); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (buffer_size - buffer_pos > PAGE_SIZE) 54862306a36Sopenharmony_ci chunk = PAGE_SIZE; 54962306a36Sopenharmony_ci else 55062306a36Sopenharmony_ci chunk = buffer_size - buffer_pos; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci page = reiserfs_get_page(d_inode(dentry), file_pos); 55362306a36Sopenharmony_ci if (IS_ERR(page)) { 55462306a36Sopenharmony_ci err = PTR_ERR(page); 55562306a36Sopenharmony_ci goto out_unlock; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci lock_page(page); 55962306a36Sopenharmony_ci data = page_address(page); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (file_pos == 0) { 56262306a36Sopenharmony_ci struct reiserfs_xattr_header *rxh; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci skip = file_pos = sizeof(struct reiserfs_xattr_header); 56562306a36Sopenharmony_ci if (chunk + skip > PAGE_SIZE) 56662306a36Sopenharmony_ci chunk = PAGE_SIZE - skip; 56762306a36Sopenharmony_ci rxh = (struct reiserfs_xattr_header *)data; 56862306a36Sopenharmony_ci rxh->h_magic = cpu_to_le32(REISERFS_XATTR_MAGIC); 56962306a36Sopenharmony_ci rxh->h_hash = cpu_to_le32(xahash); 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci reiserfs_write_lock(inode->i_sb); 57362306a36Sopenharmony_ci err = __reiserfs_write_begin(page, page_offset, chunk + skip); 57462306a36Sopenharmony_ci if (!err) { 57562306a36Sopenharmony_ci if (buffer) 57662306a36Sopenharmony_ci memcpy(data + skip, buffer + buffer_pos, chunk); 57762306a36Sopenharmony_ci err = reiserfs_commit_write(NULL, page, page_offset, 57862306a36Sopenharmony_ci page_offset + chunk + 57962306a36Sopenharmony_ci skip); 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci reiserfs_write_unlock(inode->i_sb); 58262306a36Sopenharmony_ci unlock_page(page); 58362306a36Sopenharmony_ci reiserfs_put_page(page); 58462306a36Sopenharmony_ci buffer_pos += chunk; 58562306a36Sopenharmony_ci file_pos += chunk; 58662306a36Sopenharmony_ci skip = 0; 58762306a36Sopenharmony_ci if (err || buffer_size == 0 || !buffer) 58862306a36Sopenharmony_ci break; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci new_size = buffer_size + sizeof(struct reiserfs_xattr_header); 59262306a36Sopenharmony_ci if (!err && new_size < i_size_read(d_inode(dentry))) { 59362306a36Sopenharmony_ci struct iattr newattrs = { 59462306a36Sopenharmony_ci .ia_ctime = current_time(inode), 59562306a36Sopenharmony_ci .ia_size = new_size, 59662306a36Sopenharmony_ci .ia_valid = ATTR_SIZE | ATTR_CTIME, 59762306a36Sopenharmony_ci }; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci inode_lock_nested(d_inode(dentry), I_MUTEX_XATTR); 60062306a36Sopenharmony_ci inode_dio_wait(d_inode(dentry)); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci err = reiserfs_setattr(&nop_mnt_idmap, dentry, &newattrs); 60362306a36Sopenharmony_ci inode_unlock(d_inode(dentry)); 60462306a36Sopenharmony_ci } else 60562306a36Sopenharmony_ci update_ctime(inode); 60662306a36Sopenharmony_ciout_unlock: 60762306a36Sopenharmony_ci up_write(&REISERFS_I(inode)->i_xattr_sem); 60862306a36Sopenharmony_ci dput(dentry); 60962306a36Sopenharmony_ci return err; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci/* We need to start a transaction to maintain lock ordering */ 61362306a36Sopenharmony_ciint reiserfs_xattr_set(struct inode *inode, const char *name, 61462306a36Sopenharmony_ci const void *buffer, size_t buffer_size, int flags) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci struct reiserfs_transaction_handle th; 61862306a36Sopenharmony_ci int error, error2; 61962306a36Sopenharmony_ci size_t jbegin_count = reiserfs_xattr_nblocks(inode, buffer_size); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci /* Check before we start a transaction and then do nothing. */ 62262306a36Sopenharmony_ci if (!d_really_is_positive(REISERFS_SB(inode->i_sb)->priv_root)) 62362306a36Sopenharmony_ci return -EOPNOTSUPP; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (!(flags & XATTR_REPLACE)) 62662306a36Sopenharmony_ci jbegin_count += reiserfs_xattr_jcreate_nblocks(inode); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci reiserfs_write_lock(inode->i_sb); 62962306a36Sopenharmony_ci error = journal_begin(&th, inode->i_sb, jbegin_count); 63062306a36Sopenharmony_ci reiserfs_write_unlock(inode->i_sb); 63162306a36Sopenharmony_ci if (error) { 63262306a36Sopenharmony_ci return error; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci error = reiserfs_xattr_set_handle(&th, inode, name, 63662306a36Sopenharmony_ci buffer, buffer_size, flags); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci reiserfs_write_lock(inode->i_sb); 63962306a36Sopenharmony_ci error2 = journal_end(&th); 64062306a36Sopenharmony_ci reiserfs_write_unlock(inode->i_sb); 64162306a36Sopenharmony_ci if (error == 0) 64262306a36Sopenharmony_ci error = error2; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci return error; 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci/* 64862306a36Sopenharmony_ci * inode->i_mutex: down 64962306a36Sopenharmony_ci */ 65062306a36Sopenharmony_ciint 65162306a36Sopenharmony_cireiserfs_xattr_get(struct inode *inode, const char *name, void *buffer, 65262306a36Sopenharmony_ci size_t buffer_size) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci ssize_t err = 0; 65562306a36Sopenharmony_ci struct dentry *dentry; 65662306a36Sopenharmony_ci size_t isize; 65762306a36Sopenharmony_ci size_t file_pos = 0; 65862306a36Sopenharmony_ci size_t buffer_pos = 0; 65962306a36Sopenharmony_ci struct page *page; 66062306a36Sopenharmony_ci __u32 hash = 0; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci if (name == NULL) 66362306a36Sopenharmony_ci return -EINVAL; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci /* 66662306a36Sopenharmony_ci * We can't have xattrs attached to v1 items since they don't have 66762306a36Sopenharmony_ci * generation numbers 66862306a36Sopenharmony_ci */ 66962306a36Sopenharmony_ci if (get_inode_sd_version(inode) == STAT_DATA_V1) 67062306a36Sopenharmony_ci return -EOPNOTSUPP; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci /* 67362306a36Sopenharmony_ci * priv_root needn't be initialized during mount so allow initial 67462306a36Sopenharmony_ci * lookups to succeed. 67562306a36Sopenharmony_ci */ 67662306a36Sopenharmony_ci if (!REISERFS_SB(inode->i_sb)->priv_root) 67762306a36Sopenharmony_ci return 0; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci dentry = xattr_lookup(inode, name, XATTR_REPLACE); 68062306a36Sopenharmony_ci if (IS_ERR(dentry)) { 68162306a36Sopenharmony_ci err = PTR_ERR(dentry); 68262306a36Sopenharmony_ci goto out; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci down_read(&REISERFS_I(inode)->i_xattr_sem); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci isize = i_size_read(d_inode(dentry)); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci /* Just return the size needed */ 69062306a36Sopenharmony_ci if (buffer == NULL) { 69162306a36Sopenharmony_ci err = isize - sizeof(struct reiserfs_xattr_header); 69262306a36Sopenharmony_ci goto out_unlock; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci if (buffer_size < isize - sizeof(struct reiserfs_xattr_header)) { 69662306a36Sopenharmony_ci err = -ERANGE; 69762306a36Sopenharmony_ci goto out_unlock; 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci while (file_pos < isize) { 70162306a36Sopenharmony_ci size_t chunk; 70262306a36Sopenharmony_ci char *data; 70362306a36Sopenharmony_ci size_t skip = 0; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci if (isize - file_pos > PAGE_SIZE) 70662306a36Sopenharmony_ci chunk = PAGE_SIZE; 70762306a36Sopenharmony_ci else 70862306a36Sopenharmony_ci chunk = isize - file_pos; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci page = reiserfs_get_page(d_inode(dentry), file_pos); 71162306a36Sopenharmony_ci if (IS_ERR(page)) { 71262306a36Sopenharmony_ci err = PTR_ERR(page); 71362306a36Sopenharmony_ci goto out_unlock; 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci lock_page(page); 71762306a36Sopenharmony_ci data = page_address(page); 71862306a36Sopenharmony_ci if (file_pos == 0) { 71962306a36Sopenharmony_ci struct reiserfs_xattr_header *rxh = 72062306a36Sopenharmony_ci (struct reiserfs_xattr_header *)data; 72162306a36Sopenharmony_ci skip = file_pos = sizeof(struct reiserfs_xattr_header); 72262306a36Sopenharmony_ci chunk -= skip; 72362306a36Sopenharmony_ci /* Magic doesn't match up.. */ 72462306a36Sopenharmony_ci if (rxh->h_magic != cpu_to_le32(REISERFS_XATTR_MAGIC)) { 72562306a36Sopenharmony_ci unlock_page(page); 72662306a36Sopenharmony_ci reiserfs_put_page(page); 72762306a36Sopenharmony_ci reiserfs_warning(inode->i_sb, "jdm-20001", 72862306a36Sopenharmony_ci "Invalid magic for xattr (%s) " 72962306a36Sopenharmony_ci "associated with %k", name, 73062306a36Sopenharmony_ci INODE_PKEY(inode)); 73162306a36Sopenharmony_ci err = -EIO; 73262306a36Sopenharmony_ci goto out_unlock; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci hash = le32_to_cpu(rxh->h_hash); 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci memcpy(buffer + buffer_pos, data + skip, chunk); 73762306a36Sopenharmony_ci unlock_page(page); 73862306a36Sopenharmony_ci reiserfs_put_page(page); 73962306a36Sopenharmony_ci file_pos += chunk; 74062306a36Sopenharmony_ci buffer_pos += chunk; 74162306a36Sopenharmony_ci skip = 0; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci err = isize - sizeof(struct reiserfs_xattr_header); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (xattr_hash(buffer, isize - sizeof(struct reiserfs_xattr_header)) != 74662306a36Sopenharmony_ci hash) { 74762306a36Sopenharmony_ci reiserfs_warning(inode->i_sb, "jdm-20002", 74862306a36Sopenharmony_ci "Invalid hash for xattr (%s) associated " 74962306a36Sopenharmony_ci "with %k", name, INODE_PKEY(inode)); 75062306a36Sopenharmony_ci err = -EIO; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ciout_unlock: 75462306a36Sopenharmony_ci up_read(&REISERFS_I(inode)->i_xattr_sem); 75562306a36Sopenharmony_ci dput(dentry); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ciout: 75862306a36Sopenharmony_ci return err; 75962306a36Sopenharmony_ci} 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci/* 76262306a36Sopenharmony_ci * In order to implement different sets of xattr operations for each xattr 76362306a36Sopenharmony_ci * prefix with the generic xattr API, a filesystem should create a 76462306a36Sopenharmony_ci * null-terminated array of struct xattr_handler (one for each prefix) and 76562306a36Sopenharmony_ci * hang a pointer to it off of the s_xattr field of the superblock. 76662306a36Sopenharmony_ci * 76762306a36Sopenharmony_ci * The generic_fooxattr() functions will use this list to dispatch xattr 76862306a36Sopenharmony_ci * operations to the correct xattr_handler. 76962306a36Sopenharmony_ci */ 77062306a36Sopenharmony_ci#define for_each_xattr_handler(handlers, handler) \ 77162306a36Sopenharmony_ci for ((handler) = *(handlers)++; \ 77262306a36Sopenharmony_ci (handler) != NULL; \ 77362306a36Sopenharmony_ci (handler) = *(handlers)++) 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_cistatic inline bool reiserfs_posix_acl_list(const char *name, 77662306a36Sopenharmony_ci struct dentry *dentry) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci return (posix_acl_type(name) >= 0) && 77962306a36Sopenharmony_ci IS_POSIXACL(d_backing_inode(dentry)); 78062306a36Sopenharmony_ci} 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci/* This is the implementation for the xattr plugin infrastructure */ 78362306a36Sopenharmony_cistatic inline bool reiserfs_xattr_list(const struct xattr_handler **handlers, 78462306a36Sopenharmony_ci const char *name, struct dentry *dentry) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci if (handlers) { 78762306a36Sopenharmony_ci const struct xattr_handler *xah = NULL; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci for_each_xattr_handler(handlers, xah) { 79062306a36Sopenharmony_ci const char *prefix = xattr_prefix(xah); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci if (strncmp(prefix, name, strlen(prefix))) 79362306a36Sopenharmony_ci continue; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (!xattr_handler_can_list(xah, dentry)) 79662306a36Sopenharmony_ci return false; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci return true; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci return reiserfs_posix_acl_list(name, dentry); 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cistruct listxattr_buf { 80662306a36Sopenharmony_ci struct dir_context ctx; 80762306a36Sopenharmony_ci size_t size; 80862306a36Sopenharmony_ci size_t pos; 80962306a36Sopenharmony_ci char *buf; 81062306a36Sopenharmony_ci struct dentry *dentry; 81162306a36Sopenharmony_ci}; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_cistatic bool listxattr_filler(struct dir_context *ctx, const char *name, 81462306a36Sopenharmony_ci int namelen, loff_t offset, u64 ino, 81562306a36Sopenharmony_ci unsigned int d_type) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci struct listxattr_buf *b = 81862306a36Sopenharmony_ci container_of(ctx, struct listxattr_buf, ctx); 81962306a36Sopenharmony_ci size_t size; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci if (name[0] != '.' || 82262306a36Sopenharmony_ci (namelen != 1 && (name[1] != '.' || namelen != 2))) { 82362306a36Sopenharmony_ci if (!reiserfs_xattr_list(b->dentry->d_sb->s_xattr, name, 82462306a36Sopenharmony_ci b->dentry)) 82562306a36Sopenharmony_ci return true; 82662306a36Sopenharmony_ci size = namelen + 1; 82762306a36Sopenharmony_ci if (b->buf) { 82862306a36Sopenharmony_ci if (b->pos + size > b->size) { 82962306a36Sopenharmony_ci b->pos = -ERANGE; 83062306a36Sopenharmony_ci return false; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci memcpy(b->buf + b->pos, name, namelen); 83362306a36Sopenharmony_ci b->buf[b->pos + namelen] = 0; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci b->pos += size; 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci return true; 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci/* 84162306a36Sopenharmony_ci * Inode operation listxattr() 84262306a36Sopenharmony_ci * 84362306a36Sopenharmony_ci * We totally ignore the generic listxattr here because it would be stupid 84462306a36Sopenharmony_ci * not to. Since the xattrs are organized in a directory, we can just 84562306a36Sopenharmony_ci * readdir to find them. 84662306a36Sopenharmony_ci */ 84762306a36Sopenharmony_cissize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci struct dentry *dir; 85062306a36Sopenharmony_ci int err = 0; 85162306a36Sopenharmony_ci struct listxattr_buf buf = { 85262306a36Sopenharmony_ci .ctx.actor = listxattr_filler, 85362306a36Sopenharmony_ci .dentry = dentry, 85462306a36Sopenharmony_ci .buf = buffer, 85562306a36Sopenharmony_ci .size = buffer ? size : 0, 85662306a36Sopenharmony_ci }; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci if (d_really_is_negative(dentry)) 85962306a36Sopenharmony_ci return -EINVAL; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci if (get_inode_sd_version(d_inode(dentry)) == STAT_DATA_V1) 86262306a36Sopenharmony_ci return -EOPNOTSUPP; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci dir = open_xa_dir(d_inode(dentry), XATTR_REPLACE); 86562306a36Sopenharmony_ci if (IS_ERR(dir)) { 86662306a36Sopenharmony_ci err = PTR_ERR(dir); 86762306a36Sopenharmony_ci if (err == -ENODATA) 86862306a36Sopenharmony_ci err = 0; /* Not an error if there aren't any xattrs */ 86962306a36Sopenharmony_ci goto out; 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci inode_lock_nested(d_inode(dir), I_MUTEX_XATTR); 87362306a36Sopenharmony_ci err = reiserfs_readdir_inode(d_inode(dir), &buf.ctx); 87462306a36Sopenharmony_ci inode_unlock(d_inode(dir)); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci if (!err) 87762306a36Sopenharmony_ci err = buf.pos; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci dput(dir); 88062306a36Sopenharmony_ciout: 88162306a36Sopenharmony_ci return err; 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_cistatic int create_privroot(struct dentry *dentry) 88562306a36Sopenharmony_ci{ 88662306a36Sopenharmony_ci int err; 88762306a36Sopenharmony_ci struct inode *inode = d_inode(dentry->d_parent); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci WARN_ON_ONCE(!inode_is_locked(inode)); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci err = xattr_mkdir(inode, dentry, 0700); 89262306a36Sopenharmony_ci if (err || d_really_is_negative(dentry)) { 89362306a36Sopenharmony_ci reiserfs_warning(dentry->d_sb, "jdm-20006", 89462306a36Sopenharmony_ci "xattrs/ACLs enabled and couldn't " 89562306a36Sopenharmony_ci "find/create .reiserfs_priv. " 89662306a36Sopenharmony_ci "Failing mount."); 89762306a36Sopenharmony_ci return -EOPNOTSUPP; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci reiserfs_init_priv_inode(d_inode(dentry)); 90162306a36Sopenharmony_ci reiserfs_info(dentry->d_sb, "Created %s - reserved for xattr " 90262306a36Sopenharmony_ci "storage.\n", PRIVROOT_NAME); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci return 0; 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci#else 90862306a36Sopenharmony_ciint __init reiserfs_xattr_register_handlers(void) { return 0; } 90962306a36Sopenharmony_civoid reiserfs_xattr_unregister_handlers(void) {} 91062306a36Sopenharmony_cistatic int create_privroot(struct dentry *dentry) { return 0; } 91162306a36Sopenharmony_ci#endif 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci/* Actual operations that are exported to VFS-land */ 91462306a36Sopenharmony_ciconst struct xattr_handler *reiserfs_xattr_handlers[] = { 91562306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_FS_XATTR 91662306a36Sopenharmony_ci &reiserfs_xattr_user_handler, 91762306a36Sopenharmony_ci &reiserfs_xattr_trusted_handler, 91862306a36Sopenharmony_ci#endif 91962306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_FS_SECURITY 92062306a36Sopenharmony_ci &reiserfs_xattr_security_handler, 92162306a36Sopenharmony_ci#endif 92262306a36Sopenharmony_ci NULL 92362306a36Sopenharmony_ci}; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_cistatic int xattr_mount_check(struct super_block *s) 92662306a36Sopenharmony_ci{ 92762306a36Sopenharmony_ci /* 92862306a36Sopenharmony_ci * We need generation numbers to ensure that the oid mapping is correct 92962306a36Sopenharmony_ci * v3.5 filesystems don't have them. 93062306a36Sopenharmony_ci */ 93162306a36Sopenharmony_ci if (old_format_only(s)) { 93262306a36Sopenharmony_ci if (reiserfs_xattrs_optional(s)) { 93362306a36Sopenharmony_ci /* 93462306a36Sopenharmony_ci * Old format filesystem, but optional xattrs have 93562306a36Sopenharmony_ci * been enabled. Error out. 93662306a36Sopenharmony_ci */ 93762306a36Sopenharmony_ci reiserfs_warning(s, "jdm-2005", 93862306a36Sopenharmony_ci "xattrs/ACLs not supported " 93962306a36Sopenharmony_ci "on pre-v3.6 format filesystems. " 94062306a36Sopenharmony_ci "Failing mount."); 94162306a36Sopenharmony_ci return -EOPNOTSUPP; 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci return 0; 94662306a36Sopenharmony_ci} 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ciint reiserfs_permission(struct mnt_idmap *idmap, struct inode *inode, 94962306a36Sopenharmony_ci int mask) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci /* 95262306a36Sopenharmony_ci * We don't do permission checks on the internal objects. 95362306a36Sopenharmony_ci * Permissions are determined by the "owning" object. 95462306a36Sopenharmony_ci */ 95562306a36Sopenharmony_ci if (IS_PRIVATE(inode)) 95662306a36Sopenharmony_ci return 0; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci return generic_permission(&nop_mnt_idmap, inode, mask); 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_cistatic int xattr_hide_revalidate(struct dentry *dentry, unsigned int flags) 96262306a36Sopenharmony_ci{ 96362306a36Sopenharmony_ci return -EPERM; 96462306a36Sopenharmony_ci} 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_cistatic const struct dentry_operations xattr_lookup_poison_ops = { 96762306a36Sopenharmony_ci .d_revalidate = xattr_hide_revalidate, 96862306a36Sopenharmony_ci}; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ciint reiserfs_lookup_privroot(struct super_block *s) 97162306a36Sopenharmony_ci{ 97262306a36Sopenharmony_ci struct dentry *dentry; 97362306a36Sopenharmony_ci int err = 0; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci /* If we don't have the privroot located yet - go find it */ 97662306a36Sopenharmony_ci inode_lock(d_inode(s->s_root)); 97762306a36Sopenharmony_ci dentry = lookup_one_len(PRIVROOT_NAME, s->s_root, 97862306a36Sopenharmony_ci strlen(PRIVROOT_NAME)); 97962306a36Sopenharmony_ci if (!IS_ERR(dentry)) { 98062306a36Sopenharmony_ci REISERFS_SB(s)->priv_root = dentry; 98162306a36Sopenharmony_ci d_set_d_op(dentry, &xattr_lookup_poison_ops); 98262306a36Sopenharmony_ci if (d_really_is_positive(dentry)) 98362306a36Sopenharmony_ci reiserfs_init_priv_inode(d_inode(dentry)); 98462306a36Sopenharmony_ci } else 98562306a36Sopenharmony_ci err = PTR_ERR(dentry); 98662306a36Sopenharmony_ci inode_unlock(d_inode(s->s_root)); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci return err; 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci/* 99262306a36Sopenharmony_ci * We need to take a copy of the mount flags since things like 99362306a36Sopenharmony_ci * SB_RDONLY don't get set until *after* we're called. 99462306a36Sopenharmony_ci * mount_flags != mount_options 99562306a36Sopenharmony_ci */ 99662306a36Sopenharmony_ciint reiserfs_xattr_init(struct super_block *s, int mount_flags) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci int err = 0; 99962306a36Sopenharmony_ci struct dentry *privroot = REISERFS_SB(s)->priv_root; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci err = xattr_mount_check(s); 100262306a36Sopenharmony_ci if (err) 100362306a36Sopenharmony_ci goto error; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci if (d_really_is_negative(privroot) && !(mount_flags & SB_RDONLY)) { 100662306a36Sopenharmony_ci inode_lock(d_inode(s->s_root)); 100762306a36Sopenharmony_ci err = create_privroot(REISERFS_SB(s)->priv_root); 100862306a36Sopenharmony_ci inode_unlock(d_inode(s->s_root)); 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci if (d_really_is_positive(privroot)) { 101262306a36Sopenharmony_ci inode_lock(d_inode(privroot)); 101362306a36Sopenharmony_ci if (!REISERFS_SB(s)->xattr_root) { 101462306a36Sopenharmony_ci struct dentry *dentry; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci dentry = lookup_one_len(XAROOT_NAME, privroot, 101762306a36Sopenharmony_ci strlen(XAROOT_NAME)); 101862306a36Sopenharmony_ci if (!IS_ERR(dentry)) 101962306a36Sopenharmony_ci REISERFS_SB(s)->xattr_root = dentry; 102062306a36Sopenharmony_ci else 102162306a36Sopenharmony_ci err = PTR_ERR(dentry); 102262306a36Sopenharmony_ci } 102362306a36Sopenharmony_ci inode_unlock(d_inode(privroot)); 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_cierror: 102762306a36Sopenharmony_ci if (err) { 102862306a36Sopenharmony_ci clear_bit(REISERFS_XATTRS_USER, &REISERFS_SB(s)->s_mount_opt); 102962306a36Sopenharmony_ci clear_bit(REISERFS_POSIXACL, &REISERFS_SB(s)->s_mount_opt); 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci /* The super_block SB_POSIXACL must mirror the (no)acl mount option. */ 103362306a36Sopenharmony_ci if (reiserfs_posixacl(s)) 103462306a36Sopenharmony_ci s->s_flags |= SB_POSIXACL; 103562306a36Sopenharmony_ci else 103662306a36Sopenharmony_ci s->s_flags &= ~SB_POSIXACL; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci return err; 103962306a36Sopenharmony_ci} 1040