18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/reiserfs/xattr.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2002 by Jeff Mahoney, <jeffm@suse.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci/* 108c2ecf20Sopenharmony_ci * In order to implement EA/ACLs in a clean, backwards compatible manner, 118c2ecf20Sopenharmony_ci * they are implemented as files in a "private" directory. 128c2ecf20Sopenharmony_ci * Each EA is in it's own file, with the directory layout like so (/ is assumed 138c2ecf20Sopenharmony_ci * to be relative to fs root). Inside the /.reiserfs_priv/xattrs directory, 148c2ecf20Sopenharmony_ci * directories named using the capital-hex form of the objectid and 158c2ecf20Sopenharmony_ci * generation number are used. Inside each directory are individual files 168c2ecf20Sopenharmony_ci * named with the name of the extended attribute. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * So, for objectid 12648430, we could have: 198c2ecf20Sopenharmony_ci * /.reiserfs_priv/xattrs/C0FFEE.0/system.posix_acl_access 208c2ecf20Sopenharmony_ci * /.reiserfs_priv/xattrs/C0FFEE.0/system.posix_acl_default 218c2ecf20Sopenharmony_ci * /.reiserfs_priv/xattrs/C0FFEE.0/user.Content-Type 228c2ecf20Sopenharmony_ci * .. or similar. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * The file contents are the text of the EA. The size is known based on the 258c2ecf20Sopenharmony_ci * stat data describing the file. 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * In the case of system.posix_acl_access and system.posix_acl_default, since 288c2ecf20Sopenharmony_ci * these are special cases for filesystem ACLs, they are interpreted by the 298c2ecf20Sopenharmony_ci * kernel, in addition, they are negatively and positively cached and attached 308c2ecf20Sopenharmony_ci * to the inode so that unnecessary lookups are avoided. 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * Locking works like so: 338c2ecf20Sopenharmony_ci * Directory components (xattr root, xattr dir) are protectd by their i_mutex. 348c2ecf20Sopenharmony_ci * The xattrs themselves are protected by the xattr_sem. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include "reiserfs.h" 388c2ecf20Sopenharmony_ci#include <linux/capability.h> 398c2ecf20Sopenharmony_ci#include <linux/dcache.h> 408c2ecf20Sopenharmony_ci#include <linux/namei.h> 418c2ecf20Sopenharmony_ci#include <linux/errno.h> 428c2ecf20Sopenharmony_ci#include <linux/gfp.h> 438c2ecf20Sopenharmony_ci#include <linux/fs.h> 448c2ecf20Sopenharmony_ci#include <linux/file.h> 458c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 468c2ecf20Sopenharmony_ci#include <linux/xattr.h> 478c2ecf20Sopenharmony_ci#include "xattr.h" 488c2ecf20Sopenharmony_ci#include "acl.h" 498c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 508c2ecf20Sopenharmony_ci#include <net/checksum.h> 518c2ecf20Sopenharmony_ci#include <linux/stat.h> 528c2ecf20Sopenharmony_ci#include <linux/quotaops.h> 538c2ecf20Sopenharmony_ci#include <linux/security.h> 548c2ecf20Sopenharmony_ci#include <linux/posix_acl_xattr.h> 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define PRIVROOT_NAME ".reiserfs_priv" 578c2ecf20Sopenharmony_ci#define XAROOT_NAME "xattrs" 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* 618c2ecf20Sopenharmony_ci * Helpers for inode ops. We do this so that we don't have all the VFS 628c2ecf20Sopenharmony_ci * overhead and also for proper i_mutex annotation. 638c2ecf20Sopenharmony_ci * dir->i_mutex must be held for all of them. 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_ci#ifdef CONFIG_REISERFS_FS_XATTR 668c2ecf20Sopenharmony_cistatic int xattr_create(struct inode *dir, struct dentry *dentry, int mode) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci BUG_ON(!inode_is_locked(dir)); 698c2ecf20Sopenharmony_ci return dir->i_op->create(dir, dentry, mode, true); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci#endif 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic int xattr_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci BUG_ON(!inode_is_locked(dir)); 768c2ecf20Sopenharmony_ci return dir->i_op->mkdir(dir, dentry, mode); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* 808c2ecf20Sopenharmony_ci * We use I_MUTEX_CHILD here to silence lockdep. It's safe because xattr 818c2ecf20Sopenharmony_ci * mutation ops aren't called during rename or splace, which are the 828c2ecf20Sopenharmony_ci * only other users of I_MUTEX_CHILD. It violates the ordering, but that's 838c2ecf20Sopenharmony_ci * better than allocating another subclass just for this code. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_cistatic int xattr_unlink(struct inode *dir, struct dentry *dentry) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci int error; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci BUG_ON(!inode_is_locked(dir)); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci inode_lock_nested(d_inode(dentry), I_MUTEX_CHILD); 928c2ecf20Sopenharmony_ci error = dir->i_op->unlink(dir, dentry); 938c2ecf20Sopenharmony_ci inode_unlock(d_inode(dentry)); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (!error) 968c2ecf20Sopenharmony_ci d_delete(dentry); 978c2ecf20Sopenharmony_ci return error; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int xattr_rmdir(struct inode *dir, struct dentry *dentry) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci int error; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci BUG_ON(!inode_is_locked(dir)); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci inode_lock_nested(d_inode(dentry), I_MUTEX_CHILD); 1078c2ecf20Sopenharmony_ci error = dir->i_op->rmdir(dir, dentry); 1088c2ecf20Sopenharmony_ci if (!error) 1098c2ecf20Sopenharmony_ci d_inode(dentry)->i_flags |= S_DEAD; 1108c2ecf20Sopenharmony_ci inode_unlock(d_inode(dentry)); 1118c2ecf20Sopenharmony_ci if (!error) 1128c2ecf20Sopenharmony_ci d_delete(dentry); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return error; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#define xattr_may_create(flags) (!flags || flags & XATTR_CREATE) 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic struct dentry *open_xa_root(struct super_block *sb, int flags) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct dentry *privroot = REISERFS_SB(sb)->priv_root; 1228c2ecf20Sopenharmony_ci struct dentry *xaroot; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (d_really_is_negative(privroot)) 1258c2ecf20Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci inode_lock_nested(d_inode(privroot), I_MUTEX_XATTR); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci xaroot = dget(REISERFS_SB(sb)->xattr_root); 1308c2ecf20Sopenharmony_ci if (!xaroot) 1318c2ecf20Sopenharmony_ci xaroot = ERR_PTR(-EOPNOTSUPP); 1328c2ecf20Sopenharmony_ci else if (d_really_is_negative(xaroot)) { 1338c2ecf20Sopenharmony_ci int err = -ENODATA; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (xattr_may_create(flags)) 1368c2ecf20Sopenharmony_ci err = xattr_mkdir(d_inode(privroot), xaroot, 0700); 1378c2ecf20Sopenharmony_ci if (err) { 1388c2ecf20Sopenharmony_ci dput(xaroot); 1398c2ecf20Sopenharmony_ci xaroot = ERR_PTR(err); 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci inode_unlock(d_inode(privroot)); 1448c2ecf20Sopenharmony_ci return xaroot; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic struct dentry *open_xa_dir(const struct inode *inode, int flags) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct dentry *xaroot, *xadir; 1508c2ecf20Sopenharmony_ci char namebuf[17]; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci xaroot = open_xa_root(inode->i_sb, flags); 1538c2ecf20Sopenharmony_ci if (IS_ERR(xaroot)) 1548c2ecf20Sopenharmony_ci return xaroot; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci snprintf(namebuf, sizeof(namebuf), "%X.%X", 1578c2ecf20Sopenharmony_ci le32_to_cpu(INODE_PKEY(inode)->k_objectid), 1588c2ecf20Sopenharmony_ci inode->i_generation); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci inode_lock_nested(d_inode(xaroot), I_MUTEX_XATTR); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci xadir = lookup_one_len(namebuf, xaroot, strlen(namebuf)); 1638c2ecf20Sopenharmony_ci if (!IS_ERR(xadir) && d_really_is_negative(xadir)) { 1648c2ecf20Sopenharmony_ci int err = -ENODATA; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (xattr_may_create(flags)) 1678c2ecf20Sopenharmony_ci err = xattr_mkdir(d_inode(xaroot), xadir, 0700); 1688c2ecf20Sopenharmony_ci if (err) { 1698c2ecf20Sopenharmony_ci dput(xadir); 1708c2ecf20Sopenharmony_ci xadir = ERR_PTR(err); 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci inode_unlock(d_inode(xaroot)); 1758c2ecf20Sopenharmony_ci dput(xaroot); 1768c2ecf20Sopenharmony_ci return xadir; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/* 1808c2ecf20Sopenharmony_ci * The following are side effects of other operations that aren't explicitly 1818c2ecf20Sopenharmony_ci * modifying extended attributes. This includes operations such as permissions 1828c2ecf20Sopenharmony_ci * or ownership changes, object deletions, etc. 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_cistruct reiserfs_dentry_buf { 1858c2ecf20Sopenharmony_ci struct dir_context ctx; 1868c2ecf20Sopenharmony_ci struct dentry *xadir; 1878c2ecf20Sopenharmony_ci int count; 1888c2ecf20Sopenharmony_ci int err; 1898c2ecf20Sopenharmony_ci struct dentry *dentries[8]; 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic int 1938c2ecf20Sopenharmony_cifill_with_dentries(struct dir_context *ctx, const char *name, int namelen, 1948c2ecf20Sopenharmony_ci loff_t offset, u64 ino, unsigned int d_type) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct reiserfs_dentry_buf *dbuf = 1978c2ecf20Sopenharmony_ci container_of(ctx, struct reiserfs_dentry_buf, ctx); 1988c2ecf20Sopenharmony_ci struct dentry *dentry; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci WARN_ON_ONCE(!inode_is_locked(d_inode(dbuf->xadir))); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (dbuf->count == ARRAY_SIZE(dbuf->dentries)) 2038c2ecf20Sopenharmony_ci return -ENOSPC; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (name[0] == '.' && (namelen < 2 || 2068c2ecf20Sopenharmony_ci (namelen == 2 && name[1] == '.'))) 2078c2ecf20Sopenharmony_ci return 0; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci dentry = lookup_one_len(name, dbuf->xadir, namelen); 2108c2ecf20Sopenharmony_ci if (IS_ERR(dentry)) { 2118c2ecf20Sopenharmony_ci dbuf->err = PTR_ERR(dentry); 2128c2ecf20Sopenharmony_ci return PTR_ERR(dentry); 2138c2ecf20Sopenharmony_ci } else if (d_really_is_negative(dentry)) { 2148c2ecf20Sopenharmony_ci /* A directory entry exists, but no file? */ 2158c2ecf20Sopenharmony_ci reiserfs_error(dentry->d_sb, "xattr-20003", 2168c2ecf20Sopenharmony_ci "Corrupted directory: xattr %pd listed but " 2178c2ecf20Sopenharmony_ci "not found for file %pd.\n", 2188c2ecf20Sopenharmony_ci dentry, dbuf->xadir); 2198c2ecf20Sopenharmony_ci dput(dentry); 2208c2ecf20Sopenharmony_ci dbuf->err = -EIO; 2218c2ecf20Sopenharmony_ci return -EIO; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci dbuf->dentries[dbuf->count++] = dentry; 2258c2ecf20Sopenharmony_ci return 0; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic void 2298c2ecf20Sopenharmony_cicleanup_dentry_buf(struct reiserfs_dentry_buf *buf) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci int i; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci for (i = 0; i < buf->count; i++) 2348c2ecf20Sopenharmony_ci if (buf->dentries[i]) 2358c2ecf20Sopenharmony_ci dput(buf->dentries[i]); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int reiserfs_for_each_xattr(struct inode *inode, 2398c2ecf20Sopenharmony_ci int (*action)(struct dentry *, void *), 2408c2ecf20Sopenharmony_ci void *data) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct dentry *dir; 2438c2ecf20Sopenharmony_ci int i, err = 0; 2448c2ecf20Sopenharmony_ci struct reiserfs_dentry_buf buf = { 2458c2ecf20Sopenharmony_ci .ctx.actor = fill_with_dentries, 2468c2ecf20Sopenharmony_ci }; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* Skip out, an xattr has no xattrs associated with it */ 2498c2ecf20Sopenharmony_ci if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) 2508c2ecf20Sopenharmony_ci return 0; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci dir = open_xa_dir(inode, XATTR_REPLACE); 2538c2ecf20Sopenharmony_ci if (IS_ERR(dir)) { 2548c2ecf20Sopenharmony_ci err = PTR_ERR(dir); 2558c2ecf20Sopenharmony_ci goto out; 2568c2ecf20Sopenharmony_ci } else if (d_really_is_negative(dir)) { 2578c2ecf20Sopenharmony_ci err = 0; 2588c2ecf20Sopenharmony_ci goto out_dir; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci inode_lock_nested(d_inode(dir), I_MUTEX_XATTR); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci buf.xadir = dir; 2648c2ecf20Sopenharmony_ci while (1) { 2658c2ecf20Sopenharmony_ci err = reiserfs_readdir_inode(d_inode(dir), &buf.ctx); 2668c2ecf20Sopenharmony_ci if (err) 2678c2ecf20Sopenharmony_ci break; 2688c2ecf20Sopenharmony_ci if (buf.err) { 2698c2ecf20Sopenharmony_ci err = buf.err; 2708c2ecf20Sopenharmony_ci break; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci if (!buf.count) 2738c2ecf20Sopenharmony_ci break; 2748c2ecf20Sopenharmony_ci for (i = 0; !err && i < buf.count && buf.dentries[i]; i++) { 2758c2ecf20Sopenharmony_ci struct dentry *dentry = buf.dentries[i]; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (!d_is_dir(dentry)) 2788c2ecf20Sopenharmony_ci err = action(dentry, data); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci dput(dentry); 2818c2ecf20Sopenharmony_ci buf.dentries[i] = NULL; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci if (err) 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci buf.count = 0; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci inode_unlock(d_inode(dir)); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci cleanup_dentry_buf(&buf); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (!err) { 2928c2ecf20Sopenharmony_ci /* 2938c2ecf20Sopenharmony_ci * We start a transaction here to avoid a ABBA situation 2948c2ecf20Sopenharmony_ci * between the xattr root's i_mutex and the journal lock. 2958c2ecf20Sopenharmony_ci * This doesn't incur much additional overhead since the 2968c2ecf20Sopenharmony_ci * new transaction will just nest inside the 2978c2ecf20Sopenharmony_ci * outer transaction. 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_ci int blocks = JOURNAL_PER_BALANCE_CNT * 2 + 2 + 3008c2ecf20Sopenharmony_ci 4 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb); 3018c2ecf20Sopenharmony_ci struct reiserfs_transaction_handle th; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci reiserfs_write_lock(inode->i_sb); 3048c2ecf20Sopenharmony_ci err = journal_begin(&th, inode->i_sb, blocks); 3058c2ecf20Sopenharmony_ci reiserfs_write_unlock(inode->i_sb); 3068c2ecf20Sopenharmony_ci if (!err) { 3078c2ecf20Sopenharmony_ci int jerror; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci inode_lock_nested(d_inode(dir->d_parent), 3108c2ecf20Sopenharmony_ci I_MUTEX_XATTR); 3118c2ecf20Sopenharmony_ci err = action(dir, data); 3128c2ecf20Sopenharmony_ci reiserfs_write_lock(inode->i_sb); 3138c2ecf20Sopenharmony_ci jerror = journal_end(&th); 3148c2ecf20Sopenharmony_ci reiserfs_write_unlock(inode->i_sb); 3158c2ecf20Sopenharmony_ci inode_unlock(d_inode(dir->d_parent)); 3168c2ecf20Sopenharmony_ci err = jerror ?: err; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ciout_dir: 3208c2ecf20Sopenharmony_ci dput(dir); 3218c2ecf20Sopenharmony_ciout: 3228c2ecf20Sopenharmony_ci /* 3238c2ecf20Sopenharmony_ci * -ENODATA: this object doesn't have any xattrs 3248c2ecf20Sopenharmony_ci * -EOPNOTSUPP: this file system doesn't have xattrs enabled on disk. 3258c2ecf20Sopenharmony_ci * Neither are errors 3268c2ecf20Sopenharmony_ci */ 3278c2ecf20Sopenharmony_ci if (err == -ENODATA || err == -EOPNOTSUPP) 3288c2ecf20Sopenharmony_ci err = 0; 3298c2ecf20Sopenharmony_ci return err; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic int delete_one_xattr(struct dentry *dentry, void *data) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct inode *dir = d_inode(dentry->d_parent); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* This is the xattr dir, handle specially. */ 3378c2ecf20Sopenharmony_ci if (d_is_dir(dentry)) 3388c2ecf20Sopenharmony_ci return xattr_rmdir(dir, dentry); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci return xattr_unlink(dir, dentry); 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic int chown_one_xattr(struct dentry *dentry, void *data) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct iattr *attrs = data; 3468c2ecf20Sopenharmony_ci int ia_valid = attrs->ia_valid; 3478c2ecf20Sopenharmony_ci int err; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* 3508c2ecf20Sopenharmony_ci * We only want the ownership bits. Otherwise, we'll do 3518c2ecf20Sopenharmony_ci * things like change a directory to a regular file if 3528c2ecf20Sopenharmony_ci * ATTR_MODE is set. 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_ci attrs->ia_valid &= (ATTR_UID|ATTR_GID); 3558c2ecf20Sopenharmony_ci err = reiserfs_setattr(dentry, attrs); 3568c2ecf20Sopenharmony_ci attrs->ia_valid = ia_valid; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci return err; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci/* No i_mutex, but the inode is unconnected. */ 3628c2ecf20Sopenharmony_ciint reiserfs_delete_xattrs(struct inode *inode) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci int err = reiserfs_for_each_xattr(inode, delete_one_xattr, NULL); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (err) 3678c2ecf20Sopenharmony_ci reiserfs_warning(inode->i_sb, "jdm-20004", 3688c2ecf20Sopenharmony_ci "Couldn't delete all xattrs (%d)\n", err); 3698c2ecf20Sopenharmony_ci return err; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci/* inode->i_mutex: down */ 3738c2ecf20Sopenharmony_ciint reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci int err = reiserfs_for_each_xattr(inode, chown_one_xattr, attrs); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (err) 3788c2ecf20Sopenharmony_ci reiserfs_warning(inode->i_sb, "jdm-20007", 3798c2ecf20Sopenharmony_ci "Couldn't chown all xattrs (%d)\n", err); 3808c2ecf20Sopenharmony_ci return err; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci#ifdef CONFIG_REISERFS_FS_XATTR 3848c2ecf20Sopenharmony_ci/* 3858c2ecf20Sopenharmony_ci * Returns a dentry corresponding to a specific extended attribute file 3868c2ecf20Sopenharmony_ci * for the inode. If flags allow, the file is created. Otherwise, a 3878c2ecf20Sopenharmony_ci * valid or negative dentry, or an error is returned. 3888c2ecf20Sopenharmony_ci */ 3898c2ecf20Sopenharmony_cistatic struct dentry *xattr_lookup(struct inode *inode, const char *name, 3908c2ecf20Sopenharmony_ci int flags) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct dentry *xadir, *xafile; 3938c2ecf20Sopenharmony_ci int err = 0; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci xadir = open_xa_dir(inode, flags); 3968c2ecf20Sopenharmony_ci if (IS_ERR(xadir)) 3978c2ecf20Sopenharmony_ci return ERR_CAST(xadir); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci inode_lock_nested(d_inode(xadir), I_MUTEX_XATTR); 4008c2ecf20Sopenharmony_ci xafile = lookup_one_len(name, xadir, strlen(name)); 4018c2ecf20Sopenharmony_ci if (IS_ERR(xafile)) { 4028c2ecf20Sopenharmony_ci err = PTR_ERR(xafile); 4038c2ecf20Sopenharmony_ci goto out; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (d_really_is_positive(xafile) && (flags & XATTR_CREATE)) 4078c2ecf20Sopenharmony_ci err = -EEXIST; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (d_really_is_negative(xafile)) { 4108c2ecf20Sopenharmony_ci err = -ENODATA; 4118c2ecf20Sopenharmony_ci if (xattr_may_create(flags)) 4128c2ecf20Sopenharmony_ci err = xattr_create(d_inode(xadir), xafile, 4138c2ecf20Sopenharmony_ci 0700|S_IFREG); 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (err) 4178c2ecf20Sopenharmony_ci dput(xafile); 4188c2ecf20Sopenharmony_ciout: 4198c2ecf20Sopenharmony_ci inode_unlock(d_inode(xadir)); 4208c2ecf20Sopenharmony_ci dput(xadir); 4218c2ecf20Sopenharmony_ci if (err) 4228c2ecf20Sopenharmony_ci return ERR_PTR(err); 4238c2ecf20Sopenharmony_ci return xafile; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci/* Internal operations on file data */ 4278c2ecf20Sopenharmony_cistatic inline void reiserfs_put_page(struct page *page) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci kunmap(page); 4308c2ecf20Sopenharmony_ci put_page(page); 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic struct page *reiserfs_get_page(struct inode *dir, size_t n) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci struct address_space *mapping = dir->i_mapping; 4368c2ecf20Sopenharmony_ci struct page *page; 4378c2ecf20Sopenharmony_ci /* 4388c2ecf20Sopenharmony_ci * We can deadlock if we try to free dentries, 4398c2ecf20Sopenharmony_ci * and an unlink/rmdir has just occurred - GFP_NOFS avoids this 4408c2ecf20Sopenharmony_ci */ 4418c2ecf20Sopenharmony_ci mapping_set_gfp_mask(mapping, GFP_NOFS); 4428c2ecf20Sopenharmony_ci page = read_mapping_page(mapping, n >> PAGE_SHIFT, NULL); 4438c2ecf20Sopenharmony_ci if (!IS_ERR(page)) { 4448c2ecf20Sopenharmony_ci kmap(page); 4458c2ecf20Sopenharmony_ci if (PageError(page)) 4468c2ecf20Sopenharmony_ci goto fail; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci return page; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cifail: 4518c2ecf20Sopenharmony_ci reiserfs_put_page(page); 4528c2ecf20Sopenharmony_ci return ERR_PTR(-EIO); 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic inline __u32 xattr_hash(const char *msg, int len) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci /* 4588c2ecf20Sopenharmony_ci * csum_partial() gives different results for little-endian and 4598c2ecf20Sopenharmony_ci * big endian hosts. Images created on little-endian hosts and 4608c2ecf20Sopenharmony_ci * mounted on big-endian hosts(and vice versa) will see csum mismatches 4618c2ecf20Sopenharmony_ci * when trying to fetch xattrs. Treating the hash as __wsum_t would 4628c2ecf20Sopenharmony_ci * lower the frequency of mismatch. This is an endianness bug in 4638c2ecf20Sopenharmony_ci * reiserfs. The return statement would result in a sparse warning. Do 4648c2ecf20Sopenharmony_ci * not fix the sparse warning so as to not hide a reminder of the bug. 4658c2ecf20Sopenharmony_ci */ 4668c2ecf20Sopenharmony_ci return csum_partial(msg, len, 0); 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ciint reiserfs_commit_write(struct file *f, struct page *page, 4708c2ecf20Sopenharmony_ci unsigned from, unsigned to); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic void update_ctime(struct inode *inode) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci struct timespec64 now = current_time(inode); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (inode_unhashed(inode) || !inode->i_nlink || 4778c2ecf20Sopenharmony_ci timespec64_equal(&inode->i_ctime, &now)) 4788c2ecf20Sopenharmony_ci return; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci inode->i_ctime = current_time(inode); 4818c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 4828c2ecf20Sopenharmony_ci} 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_cistatic int lookup_and_delete_xattr(struct inode *inode, const char *name) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci int err = 0; 4878c2ecf20Sopenharmony_ci struct dentry *dentry, *xadir; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci xadir = open_xa_dir(inode, XATTR_REPLACE); 4908c2ecf20Sopenharmony_ci if (IS_ERR(xadir)) 4918c2ecf20Sopenharmony_ci return PTR_ERR(xadir); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci inode_lock_nested(d_inode(xadir), I_MUTEX_XATTR); 4948c2ecf20Sopenharmony_ci dentry = lookup_one_len(name, xadir, strlen(name)); 4958c2ecf20Sopenharmony_ci if (IS_ERR(dentry)) { 4968c2ecf20Sopenharmony_ci err = PTR_ERR(dentry); 4978c2ecf20Sopenharmony_ci goto out_dput; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (d_really_is_positive(dentry)) { 5018c2ecf20Sopenharmony_ci err = xattr_unlink(d_inode(xadir), dentry); 5028c2ecf20Sopenharmony_ci update_ctime(inode); 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci dput(dentry); 5068c2ecf20Sopenharmony_ciout_dput: 5078c2ecf20Sopenharmony_ci inode_unlock(d_inode(xadir)); 5088c2ecf20Sopenharmony_ci dput(xadir); 5098c2ecf20Sopenharmony_ci return err; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci/* Generic extended attribute operations that can be used by xa plugins */ 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci/* 5168c2ecf20Sopenharmony_ci * inode->i_mutex: down 5178c2ecf20Sopenharmony_ci */ 5188c2ecf20Sopenharmony_ciint 5198c2ecf20Sopenharmony_cireiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th, 5208c2ecf20Sopenharmony_ci struct inode *inode, const char *name, 5218c2ecf20Sopenharmony_ci const void *buffer, size_t buffer_size, int flags) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci int err = 0; 5248c2ecf20Sopenharmony_ci struct dentry *dentry; 5258c2ecf20Sopenharmony_ci struct page *page; 5268c2ecf20Sopenharmony_ci char *data; 5278c2ecf20Sopenharmony_ci size_t file_pos = 0; 5288c2ecf20Sopenharmony_ci size_t buffer_pos = 0; 5298c2ecf20Sopenharmony_ci size_t new_size; 5308c2ecf20Sopenharmony_ci __u32 xahash = 0; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (get_inode_sd_version(inode) == STAT_DATA_V1) 5338c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (!buffer) { 5368c2ecf20Sopenharmony_ci err = lookup_and_delete_xattr(inode, name); 5378c2ecf20Sopenharmony_ci return err; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci dentry = xattr_lookup(inode, name, flags); 5418c2ecf20Sopenharmony_ci if (IS_ERR(dentry)) 5428c2ecf20Sopenharmony_ci return PTR_ERR(dentry); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci down_write(&REISERFS_I(inode)->i_xattr_sem); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci xahash = xattr_hash(buffer, buffer_size); 5478c2ecf20Sopenharmony_ci while (buffer_pos < buffer_size || buffer_pos == 0) { 5488c2ecf20Sopenharmony_ci size_t chunk; 5498c2ecf20Sopenharmony_ci size_t skip = 0; 5508c2ecf20Sopenharmony_ci size_t page_offset = (file_pos & (PAGE_SIZE - 1)); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (buffer_size - buffer_pos > PAGE_SIZE) 5538c2ecf20Sopenharmony_ci chunk = PAGE_SIZE; 5548c2ecf20Sopenharmony_ci else 5558c2ecf20Sopenharmony_ci chunk = buffer_size - buffer_pos; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci page = reiserfs_get_page(d_inode(dentry), file_pos); 5588c2ecf20Sopenharmony_ci if (IS_ERR(page)) { 5598c2ecf20Sopenharmony_ci err = PTR_ERR(page); 5608c2ecf20Sopenharmony_ci goto out_unlock; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci lock_page(page); 5648c2ecf20Sopenharmony_ci data = page_address(page); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci if (file_pos == 0) { 5678c2ecf20Sopenharmony_ci struct reiserfs_xattr_header *rxh; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci skip = file_pos = sizeof(struct reiserfs_xattr_header); 5708c2ecf20Sopenharmony_ci if (chunk + skip > PAGE_SIZE) 5718c2ecf20Sopenharmony_ci chunk = PAGE_SIZE - skip; 5728c2ecf20Sopenharmony_ci rxh = (struct reiserfs_xattr_header *)data; 5738c2ecf20Sopenharmony_ci rxh->h_magic = cpu_to_le32(REISERFS_XATTR_MAGIC); 5748c2ecf20Sopenharmony_ci rxh->h_hash = cpu_to_le32(xahash); 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci reiserfs_write_lock(inode->i_sb); 5788c2ecf20Sopenharmony_ci err = __reiserfs_write_begin(page, page_offset, chunk + skip); 5798c2ecf20Sopenharmony_ci if (!err) { 5808c2ecf20Sopenharmony_ci if (buffer) 5818c2ecf20Sopenharmony_ci memcpy(data + skip, buffer + buffer_pos, chunk); 5828c2ecf20Sopenharmony_ci err = reiserfs_commit_write(NULL, page, page_offset, 5838c2ecf20Sopenharmony_ci page_offset + chunk + 5848c2ecf20Sopenharmony_ci skip); 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci reiserfs_write_unlock(inode->i_sb); 5878c2ecf20Sopenharmony_ci unlock_page(page); 5888c2ecf20Sopenharmony_ci reiserfs_put_page(page); 5898c2ecf20Sopenharmony_ci buffer_pos += chunk; 5908c2ecf20Sopenharmony_ci file_pos += chunk; 5918c2ecf20Sopenharmony_ci skip = 0; 5928c2ecf20Sopenharmony_ci if (err || buffer_size == 0 || !buffer) 5938c2ecf20Sopenharmony_ci break; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci new_size = buffer_size + sizeof(struct reiserfs_xattr_header); 5978c2ecf20Sopenharmony_ci if (!err && new_size < i_size_read(d_inode(dentry))) { 5988c2ecf20Sopenharmony_ci struct iattr newattrs = { 5998c2ecf20Sopenharmony_ci .ia_ctime = current_time(inode), 6008c2ecf20Sopenharmony_ci .ia_size = new_size, 6018c2ecf20Sopenharmony_ci .ia_valid = ATTR_SIZE | ATTR_CTIME, 6028c2ecf20Sopenharmony_ci }; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci inode_lock_nested(d_inode(dentry), I_MUTEX_XATTR); 6058c2ecf20Sopenharmony_ci inode_dio_wait(d_inode(dentry)); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci err = reiserfs_setattr(dentry, &newattrs); 6088c2ecf20Sopenharmony_ci inode_unlock(d_inode(dentry)); 6098c2ecf20Sopenharmony_ci } else 6108c2ecf20Sopenharmony_ci update_ctime(inode); 6118c2ecf20Sopenharmony_ciout_unlock: 6128c2ecf20Sopenharmony_ci up_write(&REISERFS_I(inode)->i_xattr_sem); 6138c2ecf20Sopenharmony_ci dput(dentry); 6148c2ecf20Sopenharmony_ci return err; 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci/* We need to start a transaction to maintain lock ordering */ 6188c2ecf20Sopenharmony_ciint reiserfs_xattr_set(struct inode *inode, const char *name, 6198c2ecf20Sopenharmony_ci const void *buffer, size_t buffer_size, int flags) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci struct reiserfs_transaction_handle th; 6238c2ecf20Sopenharmony_ci int error, error2; 6248c2ecf20Sopenharmony_ci size_t jbegin_count = reiserfs_xattr_nblocks(inode, buffer_size); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* Check before we start a transaction and then do nothing. */ 6278c2ecf20Sopenharmony_ci if (!d_really_is_positive(REISERFS_SB(inode->i_sb)->priv_root)) 6288c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci if (!(flags & XATTR_REPLACE)) 6318c2ecf20Sopenharmony_ci jbegin_count += reiserfs_xattr_jcreate_nblocks(inode); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci reiserfs_write_lock(inode->i_sb); 6348c2ecf20Sopenharmony_ci error = journal_begin(&th, inode->i_sb, jbegin_count); 6358c2ecf20Sopenharmony_ci reiserfs_write_unlock(inode->i_sb); 6368c2ecf20Sopenharmony_ci if (error) { 6378c2ecf20Sopenharmony_ci return error; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci error = reiserfs_xattr_set_handle(&th, inode, name, 6418c2ecf20Sopenharmony_ci buffer, buffer_size, flags); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci reiserfs_write_lock(inode->i_sb); 6448c2ecf20Sopenharmony_ci error2 = journal_end(&th); 6458c2ecf20Sopenharmony_ci reiserfs_write_unlock(inode->i_sb); 6468c2ecf20Sopenharmony_ci if (error == 0) 6478c2ecf20Sopenharmony_ci error = error2; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci return error; 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci/* 6538c2ecf20Sopenharmony_ci * inode->i_mutex: down 6548c2ecf20Sopenharmony_ci */ 6558c2ecf20Sopenharmony_ciint 6568c2ecf20Sopenharmony_cireiserfs_xattr_get(struct inode *inode, const char *name, void *buffer, 6578c2ecf20Sopenharmony_ci size_t buffer_size) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci ssize_t err = 0; 6608c2ecf20Sopenharmony_ci struct dentry *dentry; 6618c2ecf20Sopenharmony_ci size_t isize; 6628c2ecf20Sopenharmony_ci size_t file_pos = 0; 6638c2ecf20Sopenharmony_ci size_t buffer_pos = 0; 6648c2ecf20Sopenharmony_ci struct page *page; 6658c2ecf20Sopenharmony_ci __u32 hash = 0; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (name == NULL) 6688c2ecf20Sopenharmony_ci return -EINVAL; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci /* 6718c2ecf20Sopenharmony_ci * We can't have xattrs attached to v1 items since they don't have 6728c2ecf20Sopenharmony_ci * generation numbers 6738c2ecf20Sopenharmony_ci */ 6748c2ecf20Sopenharmony_ci if (get_inode_sd_version(inode) == STAT_DATA_V1) 6758c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* 6788c2ecf20Sopenharmony_ci * priv_root needn't be initialized during mount so allow initial 6798c2ecf20Sopenharmony_ci * lookups to succeed. 6808c2ecf20Sopenharmony_ci */ 6818c2ecf20Sopenharmony_ci if (!REISERFS_SB(inode->i_sb)->priv_root) 6828c2ecf20Sopenharmony_ci return 0; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci dentry = xattr_lookup(inode, name, XATTR_REPLACE); 6858c2ecf20Sopenharmony_ci if (IS_ERR(dentry)) { 6868c2ecf20Sopenharmony_ci err = PTR_ERR(dentry); 6878c2ecf20Sopenharmony_ci goto out; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci down_read(&REISERFS_I(inode)->i_xattr_sem); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci isize = i_size_read(d_inode(dentry)); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci /* Just return the size needed */ 6958c2ecf20Sopenharmony_ci if (buffer == NULL) { 6968c2ecf20Sopenharmony_ci err = isize - sizeof(struct reiserfs_xattr_header); 6978c2ecf20Sopenharmony_ci goto out_unlock; 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (buffer_size < isize - sizeof(struct reiserfs_xattr_header)) { 7018c2ecf20Sopenharmony_ci err = -ERANGE; 7028c2ecf20Sopenharmony_ci goto out_unlock; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci while (file_pos < isize) { 7068c2ecf20Sopenharmony_ci size_t chunk; 7078c2ecf20Sopenharmony_ci char *data; 7088c2ecf20Sopenharmony_ci size_t skip = 0; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci if (isize - file_pos > PAGE_SIZE) 7118c2ecf20Sopenharmony_ci chunk = PAGE_SIZE; 7128c2ecf20Sopenharmony_ci else 7138c2ecf20Sopenharmony_ci chunk = isize - file_pos; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci page = reiserfs_get_page(d_inode(dentry), file_pos); 7168c2ecf20Sopenharmony_ci if (IS_ERR(page)) { 7178c2ecf20Sopenharmony_ci err = PTR_ERR(page); 7188c2ecf20Sopenharmony_ci goto out_unlock; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci lock_page(page); 7228c2ecf20Sopenharmony_ci data = page_address(page); 7238c2ecf20Sopenharmony_ci if (file_pos == 0) { 7248c2ecf20Sopenharmony_ci struct reiserfs_xattr_header *rxh = 7258c2ecf20Sopenharmony_ci (struct reiserfs_xattr_header *)data; 7268c2ecf20Sopenharmony_ci skip = file_pos = sizeof(struct reiserfs_xattr_header); 7278c2ecf20Sopenharmony_ci chunk -= skip; 7288c2ecf20Sopenharmony_ci /* Magic doesn't match up.. */ 7298c2ecf20Sopenharmony_ci if (rxh->h_magic != cpu_to_le32(REISERFS_XATTR_MAGIC)) { 7308c2ecf20Sopenharmony_ci unlock_page(page); 7318c2ecf20Sopenharmony_ci reiserfs_put_page(page); 7328c2ecf20Sopenharmony_ci reiserfs_warning(inode->i_sb, "jdm-20001", 7338c2ecf20Sopenharmony_ci "Invalid magic for xattr (%s) " 7348c2ecf20Sopenharmony_ci "associated with %k", name, 7358c2ecf20Sopenharmony_ci INODE_PKEY(inode)); 7368c2ecf20Sopenharmony_ci err = -EIO; 7378c2ecf20Sopenharmony_ci goto out_unlock; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci hash = le32_to_cpu(rxh->h_hash); 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci memcpy(buffer + buffer_pos, data + skip, chunk); 7428c2ecf20Sopenharmony_ci unlock_page(page); 7438c2ecf20Sopenharmony_ci reiserfs_put_page(page); 7448c2ecf20Sopenharmony_ci file_pos += chunk; 7458c2ecf20Sopenharmony_ci buffer_pos += chunk; 7468c2ecf20Sopenharmony_ci skip = 0; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci err = isize - sizeof(struct reiserfs_xattr_header); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci if (xattr_hash(buffer, isize - sizeof(struct reiserfs_xattr_header)) != 7518c2ecf20Sopenharmony_ci hash) { 7528c2ecf20Sopenharmony_ci reiserfs_warning(inode->i_sb, "jdm-20002", 7538c2ecf20Sopenharmony_ci "Invalid hash for xattr (%s) associated " 7548c2ecf20Sopenharmony_ci "with %k", name, INODE_PKEY(inode)); 7558c2ecf20Sopenharmony_ci err = -EIO; 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ciout_unlock: 7598c2ecf20Sopenharmony_ci up_read(&REISERFS_I(inode)->i_xattr_sem); 7608c2ecf20Sopenharmony_ci dput(dentry); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ciout: 7638c2ecf20Sopenharmony_ci return err; 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci/* 7678c2ecf20Sopenharmony_ci * In order to implement different sets of xattr operations for each xattr 7688c2ecf20Sopenharmony_ci * prefix with the generic xattr API, a filesystem should create a 7698c2ecf20Sopenharmony_ci * null-terminated array of struct xattr_handler (one for each prefix) and 7708c2ecf20Sopenharmony_ci * hang a pointer to it off of the s_xattr field of the superblock. 7718c2ecf20Sopenharmony_ci * 7728c2ecf20Sopenharmony_ci * The generic_fooxattr() functions will use this list to dispatch xattr 7738c2ecf20Sopenharmony_ci * operations to the correct xattr_handler. 7748c2ecf20Sopenharmony_ci */ 7758c2ecf20Sopenharmony_ci#define for_each_xattr_handler(handlers, handler) \ 7768c2ecf20Sopenharmony_ci for ((handler) = *(handlers)++; \ 7778c2ecf20Sopenharmony_ci (handler) != NULL; \ 7788c2ecf20Sopenharmony_ci (handler) = *(handlers)++) 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci/* This is the implementation for the xattr plugin infrastructure */ 7818c2ecf20Sopenharmony_cistatic inline const struct xattr_handler * 7828c2ecf20Sopenharmony_cifind_xattr_handler_prefix(const struct xattr_handler **handlers, 7838c2ecf20Sopenharmony_ci const char *name) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci const struct xattr_handler *xah; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci if (!handlers) 7888c2ecf20Sopenharmony_ci return NULL; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci for_each_xattr_handler(handlers, xah) { 7918c2ecf20Sopenharmony_ci const char *prefix = xattr_prefix(xah); 7928c2ecf20Sopenharmony_ci if (strncmp(prefix, name, strlen(prefix)) == 0) 7938c2ecf20Sopenharmony_ci break; 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci return xah; 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistruct listxattr_buf { 8008c2ecf20Sopenharmony_ci struct dir_context ctx; 8018c2ecf20Sopenharmony_ci size_t size; 8028c2ecf20Sopenharmony_ci size_t pos; 8038c2ecf20Sopenharmony_ci char *buf; 8048c2ecf20Sopenharmony_ci struct dentry *dentry; 8058c2ecf20Sopenharmony_ci}; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_cistatic int listxattr_filler(struct dir_context *ctx, const char *name, 8088c2ecf20Sopenharmony_ci int namelen, loff_t offset, u64 ino, 8098c2ecf20Sopenharmony_ci unsigned int d_type) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci struct listxattr_buf *b = 8128c2ecf20Sopenharmony_ci container_of(ctx, struct listxattr_buf, ctx); 8138c2ecf20Sopenharmony_ci size_t size; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci if (name[0] != '.' || 8168c2ecf20Sopenharmony_ci (namelen != 1 && (name[1] != '.' || namelen != 2))) { 8178c2ecf20Sopenharmony_ci const struct xattr_handler *handler; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci handler = find_xattr_handler_prefix(b->dentry->d_sb->s_xattr, 8208c2ecf20Sopenharmony_ci name); 8218c2ecf20Sopenharmony_ci if (!handler /* Unsupported xattr name */ || 8228c2ecf20Sopenharmony_ci (handler->list && !handler->list(b->dentry))) 8238c2ecf20Sopenharmony_ci return 0; 8248c2ecf20Sopenharmony_ci size = namelen + 1; 8258c2ecf20Sopenharmony_ci if (b->buf) { 8268c2ecf20Sopenharmony_ci if (b->pos + size > b->size) { 8278c2ecf20Sopenharmony_ci b->pos = -ERANGE; 8288c2ecf20Sopenharmony_ci return -ERANGE; 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci memcpy(b->buf + b->pos, name, namelen); 8318c2ecf20Sopenharmony_ci b->buf[b->pos + namelen] = 0; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci b->pos += size; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci return 0; 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci/* 8398c2ecf20Sopenharmony_ci * Inode operation listxattr() 8408c2ecf20Sopenharmony_ci * 8418c2ecf20Sopenharmony_ci * We totally ignore the generic listxattr here because it would be stupid 8428c2ecf20Sopenharmony_ci * not to. Since the xattrs are organized in a directory, we can just 8438c2ecf20Sopenharmony_ci * readdir to find them. 8448c2ecf20Sopenharmony_ci */ 8458c2ecf20Sopenharmony_cissize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci struct dentry *dir; 8488c2ecf20Sopenharmony_ci int err = 0; 8498c2ecf20Sopenharmony_ci struct listxattr_buf buf = { 8508c2ecf20Sopenharmony_ci .ctx.actor = listxattr_filler, 8518c2ecf20Sopenharmony_ci .dentry = dentry, 8528c2ecf20Sopenharmony_ci .buf = buffer, 8538c2ecf20Sopenharmony_ci .size = buffer ? size : 0, 8548c2ecf20Sopenharmony_ci }; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci if (d_really_is_negative(dentry)) 8578c2ecf20Sopenharmony_ci return -EINVAL; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci if (get_inode_sd_version(d_inode(dentry)) == STAT_DATA_V1) 8608c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci dir = open_xa_dir(d_inode(dentry), XATTR_REPLACE); 8638c2ecf20Sopenharmony_ci if (IS_ERR(dir)) { 8648c2ecf20Sopenharmony_ci err = PTR_ERR(dir); 8658c2ecf20Sopenharmony_ci if (err == -ENODATA) 8668c2ecf20Sopenharmony_ci err = 0; /* Not an error if there aren't any xattrs */ 8678c2ecf20Sopenharmony_ci goto out; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci inode_lock_nested(d_inode(dir), I_MUTEX_XATTR); 8718c2ecf20Sopenharmony_ci err = reiserfs_readdir_inode(d_inode(dir), &buf.ctx); 8728c2ecf20Sopenharmony_ci inode_unlock(d_inode(dir)); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci if (!err) 8758c2ecf20Sopenharmony_ci err = buf.pos; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci dput(dir); 8788c2ecf20Sopenharmony_ciout: 8798c2ecf20Sopenharmony_ci return err; 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistatic int create_privroot(struct dentry *dentry) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci int err; 8858c2ecf20Sopenharmony_ci struct inode *inode = d_inode(dentry->d_parent); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci WARN_ON_ONCE(!inode_is_locked(inode)); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci err = xattr_mkdir(inode, dentry, 0700); 8908c2ecf20Sopenharmony_ci if (err || d_really_is_negative(dentry)) { 8918c2ecf20Sopenharmony_ci reiserfs_warning(dentry->d_sb, "jdm-20006", 8928c2ecf20Sopenharmony_ci "xattrs/ACLs enabled and couldn't " 8938c2ecf20Sopenharmony_ci "find/create .reiserfs_priv. " 8948c2ecf20Sopenharmony_ci "Failing mount."); 8958c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci d_inode(dentry)->i_flags |= S_PRIVATE; 8998c2ecf20Sopenharmony_ci d_inode(dentry)->i_opflags &= ~IOP_XATTR; 9008c2ecf20Sopenharmony_ci reiserfs_info(dentry->d_sb, "Created %s - reserved for xattr " 9018c2ecf20Sopenharmony_ci "storage.\n", PRIVROOT_NAME); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci return 0; 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci#else 9078c2ecf20Sopenharmony_ciint __init reiserfs_xattr_register_handlers(void) { return 0; } 9088c2ecf20Sopenharmony_civoid reiserfs_xattr_unregister_handlers(void) {} 9098c2ecf20Sopenharmony_cistatic int create_privroot(struct dentry *dentry) { return 0; } 9108c2ecf20Sopenharmony_ci#endif 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci/* Actual operations that are exported to VFS-land */ 9138c2ecf20Sopenharmony_ciconst struct xattr_handler *reiserfs_xattr_handlers[] = { 9148c2ecf20Sopenharmony_ci#ifdef CONFIG_REISERFS_FS_XATTR 9158c2ecf20Sopenharmony_ci &reiserfs_xattr_user_handler, 9168c2ecf20Sopenharmony_ci &reiserfs_xattr_trusted_handler, 9178c2ecf20Sopenharmony_ci#endif 9188c2ecf20Sopenharmony_ci#ifdef CONFIG_REISERFS_FS_SECURITY 9198c2ecf20Sopenharmony_ci &reiserfs_xattr_security_handler, 9208c2ecf20Sopenharmony_ci#endif 9218c2ecf20Sopenharmony_ci#ifdef CONFIG_REISERFS_FS_POSIX_ACL 9228c2ecf20Sopenharmony_ci &posix_acl_access_xattr_handler, 9238c2ecf20Sopenharmony_ci &posix_acl_default_xattr_handler, 9248c2ecf20Sopenharmony_ci#endif 9258c2ecf20Sopenharmony_ci NULL 9268c2ecf20Sopenharmony_ci}; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_cistatic int xattr_mount_check(struct super_block *s) 9298c2ecf20Sopenharmony_ci{ 9308c2ecf20Sopenharmony_ci /* 9318c2ecf20Sopenharmony_ci * We need generation numbers to ensure that the oid mapping is correct 9328c2ecf20Sopenharmony_ci * v3.5 filesystems don't have them. 9338c2ecf20Sopenharmony_ci */ 9348c2ecf20Sopenharmony_ci if (old_format_only(s)) { 9358c2ecf20Sopenharmony_ci if (reiserfs_xattrs_optional(s)) { 9368c2ecf20Sopenharmony_ci /* 9378c2ecf20Sopenharmony_ci * Old format filesystem, but optional xattrs have 9388c2ecf20Sopenharmony_ci * been enabled. Error out. 9398c2ecf20Sopenharmony_ci */ 9408c2ecf20Sopenharmony_ci reiserfs_warning(s, "jdm-2005", 9418c2ecf20Sopenharmony_ci "xattrs/ACLs not supported " 9428c2ecf20Sopenharmony_ci "on pre-v3.6 format filesystems. " 9438c2ecf20Sopenharmony_ci "Failing mount."); 9448c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci return 0; 9498c2ecf20Sopenharmony_ci} 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ciint reiserfs_permission(struct inode *inode, int mask) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci /* 9548c2ecf20Sopenharmony_ci * We don't do permission checks on the internal objects. 9558c2ecf20Sopenharmony_ci * Permissions are determined by the "owning" object. 9568c2ecf20Sopenharmony_ci */ 9578c2ecf20Sopenharmony_ci if (IS_PRIVATE(inode)) 9588c2ecf20Sopenharmony_ci return 0; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci return generic_permission(inode, mask); 9618c2ecf20Sopenharmony_ci} 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_cistatic int xattr_hide_revalidate(struct dentry *dentry, unsigned int flags) 9648c2ecf20Sopenharmony_ci{ 9658c2ecf20Sopenharmony_ci return -EPERM; 9668c2ecf20Sopenharmony_ci} 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_cistatic const struct dentry_operations xattr_lookup_poison_ops = { 9698c2ecf20Sopenharmony_ci .d_revalidate = xattr_hide_revalidate, 9708c2ecf20Sopenharmony_ci}; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ciint reiserfs_lookup_privroot(struct super_block *s) 9738c2ecf20Sopenharmony_ci{ 9748c2ecf20Sopenharmony_ci struct dentry *dentry; 9758c2ecf20Sopenharmony_ci int err = 0; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci /* If we don't have the privroot located yet - go find it */ 9788c2ecf20Sopenharmony_ci inode_lock(d_inode(s->s_root)); 9798c2ecf20Sopenharmony_ci dentry = lookup_one_len(PRIVROOT_NAME, s->s_root, 9808c2ecf20Sopenharmony_ci strlen(PRIVROOT_NAME)); 9818c2ecf20Sopenharmony_ci if (!IS_ERR(dentry)) { 9828c2ecf20Sopenharmony_ci REISERFS_SB(s)->priv_root = dentry; 9838c2ecf20Sopenharmony_ci d_set_d_op(dentry, &xattr_lookup_poison_ops); 9848c2ecf20Sopenharmony_ci if (d_really_is_positive(dentry)) { 9858c2ecf20Sopenharmony_ci d_inode(dentry)->i_flags |= S_PRIVATE; 9868c2ecf20Sopenharmony_ci d_inode(dentry)->i_opflags &= ~IOP_XATTR; 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci } else 9898c2ecf20Sopenharmony_ci err = PTR_ERR(dentry); 9908c2ecf20Sopenharmony_ci inode_unlock(d_inode(s->s_root)); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci return err; 9938c2ecf20Sopenharmony_ci} 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci/* 9968c2ecf20Sopenharmony_ci * We need to take a copy of the mount flags since things like 9978c2ecf20Sopenharmony_ci * SB_RDONLY don't get set until *after* we're called. 9988c2ecf20Sopenharmony_ci * mount_flags != mount_options 9998c2ecf20Sopenharmony_ci */ 10008c2ecf20Sopenharmony_ciint reiserfs_xattr_init(struct super_block *s, int mount_flags) 10018c2ecf20Sopenharmony_ci{ 10028c2ecf20Sopenharmony_ci int err = 0; 10038c2ecf20Sopenharmony_ci struct dentry *privroot = REISERFS_SB(s)->priv_root; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci err = xattr_mount_check(s); 10068c2ecf20Sopenharmony_ci if (err) 10078c2ecf20Sopenharmony_ci goto error; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci if (d_really_is_negative(privroot) && !(mount_flags & SB_RDONLY)) { 10108c2ecf20Sopenharmony_ci inode_lock(d_inode(s->s_root)); 10118c2ecf20Sopenharmony_ci err = create_privroot(REISERFS_SB(s)->priv_root); 10128c2ecf20Sopenharmony_ci inode_unlock(d_inode(s->s_root)); 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci if (d_really_is_positive(privroot)) { 10168c2ecf20Sopenharmony_ci inode_lock(d_inode(privroot)); 10178c2ecf20Sopenharmony_ci if (!REISERFS_SB(s)->xattr_root) { 10188c2ecf20Sopenharmony_ci struct dentry *dentry; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci dentry = lookup_one_len(XAROOT_NAME, privroot, 10218c2ecf20Sopenharmony_ci strlen(XAROOT_NAME)); 10228c2ecf20Sopenharmony_ci if (!IS_ERR(dentry)) 10238c2ecf20Sopenharmony_ci REISERFS_SB(s)->xattr_root = dentry; 10248c2ecf20Sopenharmony_ci else 10258c2ecf20Sopenharmony_ci err = PTR_ERR(dentry); 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci inode_unlock(d_inode(privroot)); 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_cierror: 10318c2ecf20Sopenharmony_ci if (err) { 10328c2ecf20Sopenharmony_ci clear_bit(REISERFS_XATTRS_USER, &REISERFS_SB(s)->s_mount_opt); 10338c2ecf20Sopenharmony_ci clear_bit(REISERFS_POSIXACL, &REISERFS_SB(s)->s_mount_opt); 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci /* The super_block SB_POSIXACL must mirror the (no)acl mount option. */ 10378c2ecf20Sopenharmony_ci if (reiserfs_posixacl(s)) 10388c2ecf20Sopenharmony_ci s->s_flags |= SB_POSIXACL; 10398c2ecf20Sopenharmony_ci else 10408c2ecf20Sopenharmony_ci s->s_flags &= ~SB_POSIXACL; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci return err; 10438c2ecf20Sopenharmony_ci} 1044