162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2000-2005 Silicon Graphics, Inc. 462306a36Sopenharmony_ci * All Rights Reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include "xfs.h" 762306a36Sopenharmony_ci#include "xfs_fs.h" 862306a36Sopenharmony_ci#include "xfs_shared.h" 962306a36Sopenharmony_ci#include "xfs_format.h" 1062306a36Sopenharmony_ci#include "xfs_log_format.h" 1162306a36Sopenharmony_ci#include "xfs_trans_resv.h" 1262306a36Sopenharmony_ci#include "xfs_mount.h" 1362306a36Sopenharmony_ci#include "xfs_inode.h" 1462306a36Sopenharmony_ci#include "xfs_acl.h" 1562306a36Sopenharmony_ci#include "xfs_quota.h" 1662306a36Sopenharmony_ci#include "xfs_da_format.h" 1762306a36Sopenharmony_ci#include "xfs_da_btree.h" 1862306a36Sopenharmony_ci#include "xfs_attr.h" 1962306a36Sopenharmony_ci#include "xfs_trans.h" 2062306a36Sopenharmony_ci#include "xfs_trace.h" 2162306a36Sopenharmony_ci#include "xfs_icache.h" 2262306a36Sopenharmony_ci#include "xfs_symlink.h" 2362306a36Sopenharmony_ci#include "xfs_dir2.h" 2462306a36Sopenharmony_ci#include "xfs_iomap.h" 2562306a36Sopenharmony_ci#include "xfs_error.h" 2662306a36Sopenharmony_ci#include "xfs_ioctl.h" 2762306a36Sopenharmony_ci#include "xfs_xattr.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <linux/posix_acl.h> 3062306a36Sopenharmony_ci#include <linux/security.h> 3162306a36Sopenharmony_ci#include <linux/iversion.h> 3262306a36Sopenharmony_ci#include <linux/fiemap.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* 3562306a36Sopenharmony_ci * Directories have different lock order w.r.t. mmap_lock compared to regular 3662306a36Sopenharmony_ci * files. This is due to readdir potentially triggering page faults on a user 3762306a36Sopenharmony_ci * buffer inside filldir(), and this happens with the ilock on the directory 3862306a36Sopenharmony_ci * held. For regular files, the lock order is the other way around - the 3962306a36Sopenharmony_ci * mmap_lock is taken during the page fault, and then we lock the ilock to do 4062306a36Sopenharmony_ci * block mapping. Hence we need a different class for the directory ilock so 4162306a36Sopenharmony_ci * that lockdep can tell them apart. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_cistatic struct lock_class_key xfs_nondir_ilock_class; 4462306a36Sopenharmony_cistatic struct lock_class_key xfs_dir_ilock_class; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic int 4762306a36Sopenharmony_cixfs_initxattrs( 4862306a36Sopenharmony_ci struct inode *inode, 4962306a36Sopenharmony_ci const struct xattr *xattr_array, 5062306a36Sopenharmony_ci void *fs_info) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci const struct xattr *xattr; 5362306a36Sopenharmony_ci struct xfs_inode *ip = XFS_I(inode); 5462306a36Sopenharmony_ci int error = 0; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci for (xattr = xattr_array; xattr->name != NULL; xattr++) { 5762306a36Sopenharmony_ci struct xfs_da_args args = { 5862306a36Sopenharmony_ci .dp = ip, 5962306a36Sopenharmony_ci .attr_filter = XFS_ATTR_SECURE, 6062306a36Sopenharmony_ci .name = xattr->name, 6162306a36Sopenharmony_ci .namelen = strlen(xattr->name), 6262306a36Sopenharmony_ci .value = xattr->value, 6362306a36Sopenharmony_ci .valuelen = xattr->value_len, 6462306a36Sopenharmony_ci }; 6562306a36Sopenharmony_ci error = xfs_attr_change(&args); 6662306a36Sopenharmony_ci if (error < 0) 6762306a36Sopenharmony_ci break; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci return error; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* 7362306a36Sopenharmony_ci * Hook in SELinux. This is not quite correct yet, what we really need 7462306a36Sopenharmony_ci * here (as we do for default ACLs) is a mechanism by which creation of 7562306a36Sopenharmony_ci * these attrs can be journalled at inode creation time (along with the 7662306a36Sopenharmony_ci * inode, of course, such that log replay can't cause these to be lost). 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_ciint 7962306a36Sopenharmony_cixfs_inode_init_security( 8062306a36Sopenharmony_ci struct inode *inode, 8162306a36Sopenharmony_ci struct inode *dir, 8262306a36Sopenharmony_ci const struct qstr *qstr) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci return security_inode_init_security(inode, dir, qstr, 8562306a36Sopenharmony_ci &xfs_initxattrs, NULL); 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic void 8962306a36Sopenharmony_cixfs_dentry_to_name( 9062306a36Sopenharmony_ci struct xfs_name *namep, 9162306a36Sopenharmony_ci struct dentry *dentry) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci namep->name = dentry->d_name.name; 9462306a36Sopenharmony_ci namep->len = dentry->d_name.len; 9562306a36Sopenharmony_ci namep->type = XFS_DIR3_FT_UNKNOWN; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic int 9962306a36Sopenharmony_cixfs_dentry_mode_to_name( 10062306a36Sopenharmony_ci struct xfs_name *namep, 10162306a36Sopenharmony_ci struct dentry *dentry, 10262306a36Sopenharmony_ci int mode) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci namep->name = dentry->d_name.name; 10562306a36Sopenharmony_ci namep->len = dentry->d_name.len; 10662306a36Sopenharmony_ci namep->type = xfs_mode_to_ftype(mode); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (unlikely(namep->type == XFS_DIR3_FT_UNKNOWN)) 10962306a36Sopenharmony_ci return -EFSCORRUPTED; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ciSTATIC void 11562306a36Sopenharmony_cixfs_cleanup_inode( 11662306a36Sopenharmony_ci struct inode *dir, 11762306a36Sopenharmony_ci struct inode *inode, 11862306a36Sopenharmony_ci struct dentry *dentry) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci struct xfs_name teardown; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* Oh, the horror. 12362306a36Sopenharmony_ci * If we can't add the ACL or we fail in 12462306a36Sopenharmony_ci * xfs_inode_init_security we must back out. 12562306a36Sopenharmony_ci * ENOSPC can hit here, among other things. 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_ci xfs_dentry_to_name(&teardown, dentry); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci xfs_remove(XFS_I(dir), &teardown, XFS_I(inode)); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* 13362306a36Sopenharmony_ci * Check to see if we are likely to need an extended attribute to be added to 13462306a36Sopenharmony_ci * the inode we are about to allocate. This allows the attribute fork to be 13562306a36Sopenharmony_ci * created during the inode allocation, reducing the number of transactions we 13662306a36Sopenharmony_ci * need to do in this fast path. 13762306a36Sopenharmony_ci * 13862306a36Sopenharmony_ci * The security checks are optimistic, but not guaranteed. The two LSMs that 13962306a36Sopenharmony_ci * require xattrs to be added here (selinux and smack) are also the only two 14062306a36Sopenharmony_ci * LSMs that add a sb->s_security structure to the superblock. Hence if security 14162306a36Sopenharmony_ci * is enabled and sb->s_security is set, we have a pretty good idea that we are 14262306a36Sopenharmony_ci * going to be asked to add a security xattr immediately after allocating the 14362306a36Sopenharmony_ci * xfs inode and instantiating the VFS inode. 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_cistatic inline bool 14662306a36Sopenharmony_cixfs_create_need_xattr( 14762306a36Sopenharmony_ci struct inode *dir, 14862306a36Sopenharmony_ci struct posix_acl *default_acl, 14962306a36Sopenharmony_ci struct posix_acl *acl) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci if (acl) 15262306a36Sopenharmony_ci return true; 15362306a36Sopenharmony_ci if (default_acl) 15462306a36Sopenharmony_ci return true; 15562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SECURITY) 15662306a36Sopenharmony_ci if (dir->i_sb->s_security) 15762306a36Sopenharmony_ci return true; 15862306a36Sopenharmony_ci#endif 15962306a36Sopenharmony_ci return false; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ciSTATIC int 16462306a36Sopenharmony_cixfs_generic_create( 16562306a36Sopenharmony_ci struct mnt_idmap *idmap, 16662306a36Sopenharmony_ci struct inode *dir, 16762306a36Sopenharmony_ci struct dentry *dentry, 16862306a36Sopenharmony_ci umode_t mode, 16962306a36Sopenharmony_ci dev_t rdev, 17062306a36Sopenharmony_ci struct file *tmpfile) /* unnamed file */ 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci struct inode *inode; 17362306a36Sopenharmony_ci struct xfs_inode *ip = NULL; 17462306a36Sopenharmony_ci struct posix_acl *default_acl, *acl; 17562306a36Sopenharmony_ci struct xfs_name name; 17662306a36Sopenharmony_ci int error; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* 17962306a36Sopenharmony_ci * Irix uses Missed'em'V split, but doesn't want to see 18062306a36Sopenharmony_ci * the upper 5 bits of (14bit) major. 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci if (S_ISCHR(mode) || S_ISBLK(mode)) { 18362306a36Sopenharmony_ci if (unlikely(!sysv_valid_dev(rdev) || MAJOR(rdev) & ~0x1ff)) 18462306a36Sopenharmony_ci return -EINVAL; 18562306a36Sopenharmony_ci } else { 18662306a36Sopenharmony_ci rdev = 0; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci error = posix_acl_create(dir, &mode, &default_acl, &acl); 19062306a36Sopenharmony_ci if (error) 19162306a36Sopenharmony_ci return error; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci /* Verify mode is valid also for tmpfile case */ 19462306a36Sopenharmony_ci error = xfs_dentry_mode_to_name(&name, dentry, mode); 19562306a36Sopenharmony_ci if (unlikely(error)) 19662306a36Sopenharmony_ci goto out_free_acl; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (!tmpfile) { 19962306a36Sopenharmony_ci error = xfs_create(idmap, XFS_I(dir), &name, mode, rdev, 20062306a36Sopenharmony_ci xfs_create_need_xattr(dir, default_acl, acl), 20162306a36Sopenharmony_ci &ip); 20262306a36Sopenharmony_ci } else { 20362306a36Sopenharmony_ci error = xfs_create_tmpfile(idmap, XFS_I(dir), mode, &ip); 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci if (unlikely(error)) 20662306a36Sopenharmony_ci goto out_free_acl; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci inode = VFS_I(ip); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci error = xfs_inode_init_security(inode, dir, &dentry->d_name); 21162306a36Sopenharmony_ci if (unlikely(error)) 21262306a36Sopenharmony_ci goto out_cleanup_inode; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (default_acl) { 21562306a36Sopenharmony_ci error = __xfs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); 21662306a36Sopenharmony_ci if (error) 21762306a36Sopenharmony_ci goto out_cleanup_inode; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci if (acl) { 22062306a36Sopenharmony_ci error = __xfs_set_acl(inode, acl, ACL_TYPE_ACCESS); 22162306a36Sopenharmony_ci if (error) 22262306a36Sopenharmony_ci goto out_cleanup_inode; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci xfs_setup_iops(ip); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (tmpfile) { 22862306a36Sopenharmony_ci /* 22962306a36Sopenharmony_ci * The VFS requires that any inode fed to d_tmpfile must have 23062306a36Sopenharmony_ci * nlink == 1 so that it can decrement the nlink in d_tmpfile. 23162306a36Sopenharmony_ci * However, we created the temp file with nlink == 0 because 23262306a36Sopenharmony_ci * we're not allowed to put an inode with nlink > 0 on the 23362306a36Sopenharmony_ci * unlinked list. Therefore we have to set nlink to 1 so that 23462306a36Sopenharmony_ci * d_tmpfile can immediately set it back to zero. 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ci set_nlink(inode, 1); 23762306a36Sopenharmony_ci d_tmpfile(tmpfile, inode); 23862306a36Sopenharmony_ci } else 23962306a36Sopenharmony_ci d_instantiate(dentry, inode); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci xfs_finish_inode_setup(ip); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci out_free_acl: 24462306a36Sopenharmony_ci posix_acl_release(default_acl); 24562306a36Sopenharmony_ci posix_acl_release(acl); 24662306a36Sopenharmony_ci return error; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci out_cleanup_inode: 24962306a36Sopenharmony_ci xfs_finish_inode_setup(ip); 25062306a36Sopenharmony_ci if (!tmpfile) 25162306a36Sopenharmony_ci xfs_cleanup_inode(dir, inode, dentry); 25262306a36Sopenharmony_ci xfs_irele(ip); 25362306a36Sopenharmony_ci goto out_free_acl; 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ciSTATIC int 25762306a36Sopenharmony_cixfs_vn_mknod( 25862306a36Sopenharmony_ci struct mnt_idmap *idmap, 25962306a36Sopenharmony_ci struct inode *dir, 26062306a36Sopenharmony_ci struct dentry *dentry, 26162306a36Sopenharmony_ci umode_t mode, 26262306a36Sopenharmony_ci dev_t rdev) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci return xfs_generic_create(idmap, dir, dentry, mode, rdev, NULL); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ciSTATIC int 26862306a36Sopenharmony_cixfs_vn_create( 26962306a36Sopenharmony_ci struct mnt_idmap *idmap, 27062306a36Sopenharmony_ci struct inode *dir, 27162306a36Sopenharmony_ci struct dentry *dentry, 27262306a36Sopenharmony_ci umode_t mode, 27362306a36Sopenharmony_ci bool flags) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci return xfs_generic_create(idmap, dir, dentry, mode, 0, NULL); 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ciSTATIC int 27962306a36Sopenharmony_cixfs_vn_mkdir( 28062306a36Sopenharmony_ci struct mnt_idmap *idmap, 28162306a36Sopenharmony_ci struct inode *dir, 28262306a36Sopenharmony_ci struct dentry *dentry, 28362306a36Sopenharmony_ci umode_t mode) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci return xfs_generic_create(idmap, dir, dentry, mode | S_IFDIR, 0, NULL); 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ciSTATIC struct dentry * 28962306a36Sopenharmony_cixfs_vn_lookup( 29062306a36Sopenharmony_ci struct inode *dir, 29162306a36Sopenharmony_ci struct dentry *dentry, 29262306a36Sopenharmony_ci unsigned int flags) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci struct inode *inode; 29562306a36Sopenharmony_ci struct xfs_inode *cip; 29662306a36Sopenharmony_ci struct xfs_name name; 29762306a36Sopenharmony_ci int error; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (dentry->d_name.len >= MAXNAMELEN) 30062306a36Sopenharmony_ci return ERR_PTR(-ENAMETOOLONG); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci xfs_dentry_to_name(&name, dentry); 30362306a36Sopenharmony_ci error = xfs_lookup(XFS_I(dir), &name, &cip, NULL); 30462306a36Sopenharmony_ci if (likely(!error)) 30562306a36Sopenharmony_ci inode = VFS_I(cip); 30662306a36Sopenharmony_ci else if (likely(error == -ENOENT)) 30762306a36Sopenharmony_ci inode = NULL; 30862306a36Sopenharmony_ci else 30962306a36Sopenharmony_ci inode = ERR_PTR(error); 31062306a36Sopenharmony_ci return d_splice_alias(inode, dentry); 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ciSTATIC struct dentry * 31462306a36Sopenharmony_cixfs_vn_ci_lookup( 31562306a36Sopenharmony_ci struct inode *dir, 31662306a36Sopenharmony_ci struct dentry *dentry, 31762306a36Sopenharmony_ci unsigned int flags) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct xfs_inode *ip; 32062306a36Sopenharmony_ci struct xfs_name xname; 32162306a36Sopenharmony_ci struct xfs_name ci_name; 32262306a36Sopenharmony_ci struct qstr dname; 32362306a36Sopenharmony_ci int error; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (dentry->d_name.len >= MAXNAMELEN) 32662306a36Sopenharmony_ci return ERR_PTR(-ENAMETOOLONG); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci xfs_dentry_to_name(&xname, dentry); 32962306a36Sopenharmony_ci error = xfs_lookup(XFS_I(dir), &xname, &ip, &ci_name); 33062306a36Sopenharmony_ci if (unlikely(error)) { 33162306a36Sopenharmony_ci if (unlikely(error != -ENOENT)) 33262306a36Sopenharmony_ci return ERR_PTR(error); 33362306a36Sopenharmony_ci /* 33462306a36Sopenharmony_ci * call d_add(dentry, NULL) here when d_drop_negative_children 33562306a36Sopenharmony_ci * is called in xfs_vn_mknod (ie. allow negative dentries 33662306a36Sopenharmony_ci * with CI filesystems). 33762306a36Sopenharmony_ci */ 33862306a36Sopenharmony_ci return NULL; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* if exact match, just splice and exit */ 34262306a36Sopenharmony_ci if (!ci_name.name) 34362306a36Sopenharmony_ci return d_splice_alias(VFS_I(ip), dentry); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* else case-insensitive match... */ 34662306a36Sopenharmony_ci dname.name = ci_name.name; 34762306a36Sopenharmony_ci dname.len = ci_name.len; 34862306a36Sopenharmony_ci dentry = d_add_ci(dentry, VFS_I(ip), &dname); 34962306a36Sopenharmony_ci kmem_free(ci_name.name); 35062306a36Sopenharmony_ci return dentry; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ciSTATIC int 35462306a36Sopenharmony_cixfs_vn_link( 35562306a36Sopenharmony_ci struct dentry *old_dentry, 35662306a36Sopenharmony_ci struct inode *dir, 35762306a36Sopenharmony_ci struct dentry *dentry) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct inode *inode = d_inode(old_dentry); 36062306a36Sopenharmony_ci struct xfs_name name; 36162306a36Sopenharmony_ci int error; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci error = xfs_dentry_mode_to_name(&name, dentry, inode->i_mode); 36462306a36Sopenharmony_ci if (unlikely(error)) 36562306a36Sopenharmony_ci return error; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci error = xfs_link(XFS_I(dir), XFS_I(inode), &name); 36862306a36Sopenharmony_ci if (unlikely(error)) 36962306a36Sopenharmony_ci return error; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci ihold(inode); 37262306a36Sopenharmony_ci d_instantiate(dentry, inode); 37362306a36Sopenharmony_ci return 0; 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ciSTATIC int 37762306a36Sopenharmony_cixfs_vn_unlink( 37862306a36Sopenharmony_ci struct inode *dir, 37962306a36Sopenharmony_ci struct dentry *dentry) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci struct xfs_name name; 38262306a36Sopenharmony_ci int error; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci xfs_dentry_to_name(&name, dentry); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci error = xfs_remove(XFS_I(dir), &name, XFS_I(d_inode(dentry))); 38762306a36Sopenharmony_ci if (error) 38862306a36Sopenharmony_ci return error; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* 39162306a36Sopenharmony_ci * With unlink, the VFS makes the dentry "negative": no inode, 39262306a36Sopenharmony_ci * but still hashed. This is incompatible with case-insensitive 39362306a36Sopenharmony_ci * mode, so invalidate (unhash) the dentry in CI-mode. 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_ci if (xfs_has_asciici(XFS_M(dir->i_sb))) 39662306a36Sopenharmony_ci d_invalidate(dentry); 39762306a36Sopenharmony_ci return 0; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ciSTATIC int 40162306a36Sopenharmony_cixfs_vn_symlink( 40262306a36Sopenharmony_ci struct mnt_idmap *idmap, 40362306a36Sopenharmony_ci struct inode *dir, 40462306a36Sopenharmony_ci struct dentry *dentry, 40562306a36Sopenharmony_ci const char *symname) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct inode *inode; 40862306a36Sopenharmony_ci struct xfs_inode *cip = NULL; 40962306a36Sopenharmony_ci struct xfs_name name; 41062306a36Sopenharmony_ci int error; 41162306a36Sopenharmony_ci umode_t mode; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci mode = S_IFLNK | 41462306a36Sopenharmony_ci (irix_symlink_mode ? 0777 & ~current_umask() : S_IRWXUGO); 41562306a36Sopenharmony_ci error = xfs_dentry_mode_to_name(&name, dentry, mode); 41662306a36Sopenharmony_ci if (unlikely(error)) 41762306a36Sopenharmony_ci goto out; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci error = xfs_symlink(idmap, XFS_I(dir), &name, symname, mode, &cip); 42062306a36Sopenharmony_ci if (unlikely(error)) 42162306a36Sopenharmony_ci goto out; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci inode = VFS_I(cip); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci error = xfs_inode_init_security(inode, dir, &dentry->d_name); 42662306a36Sopenharmony_ci if (unlikely(error)) 42762306a36Sopenharmony_ci goto out_cleanup_inode; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci xfs_setup_iops(cip); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci d_instantiate(dentry, inode); 43262306a36Sopenharmony_ci xfs_finish_inode_setup(cip); 43362306a36Sopenharmony_ci return 0; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci out_cleanup_inode: 43662306a36Sopenharmony_ci xfs_finish_inode_setup(cip); 43762306a36Sopenharmony_ci xfs_cleanup_inode(dir, inode, dentry); 43862306a36Sopenharmony_ci xfs_irele(cip); 43962306a36Sopenharmony_ci out: 44062306a36Sopenharmony_ci return error; 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ciSTATIC int 44462306a36Sopenharmony_cixfs_vn_rename( 44562306a36Sopenharmony_ci struct mnt_idmap *idmap, 44662306a36Sopenharmony_ci struct inode *odir, 44762306a36Sopenharmony_ci struct dentry *odentry, 44862306a36Sopenharmony_ci struct inode *ndir, 44962306a36Sopenharmony_ci struct dentry *ndentry, 45062306a36Sopenharmony_ci unsigned int flags) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci struct inode *new_inode = d_inode(ndentry); 45362306a36Sopenharmony_ci int omode = 0; 45462306a36Sopenharmony_ci int error; 45562306a36Sopenharmony_ci struct xfs_name oname; 45662306a36Sopenharmony_ci struct xfs_name nname; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) 45962306a36Sopenharmony_ci return -EINVAL; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci /* if we are exchanging files, we need to set i_mode of both files */ 46262306a36Sopenharmony_ci if (flags & RENAME_EXCHANGE) 46362306a36Sopenharmony_ci omode = d_inode(ndentry)->i_mode; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci error = xfs_dentry_mode_to_name(&oname, odentry, omode); 46662306a36Sopenharmony_ci if (omode && unlikely(error)) 46762306a36Sopenharmony_ci return error; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci error = xfs_dentry_mode_to_name(&nname, ndentry, 47062306a36Sopenharmony_ci d_inode(odentry)->i_mode); 47162306a36Sopenharmony_ci if (unlikely(error)) 47262306a36Sopenharmony_ci return error; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return xfs_rename(idmap, XFS_I(odir), &oname, 47562306a36Sopenharmony_ci XFS_I(d_inode(odentry)), XFS_I(ndir), &nname, 47662306a36Sopenharmony_ci new_inode ? XFS_I(new_inode) : NULL, flags); 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci/* 48062306a36Sopenharmony_ci * careful here - this function can get called recursively, so 48162306a36Sopenharmony_ci * we need to be very careful about how much stack we use. 48262306a36Sopenharmony_ci * uio is kmalloced for this reason... 48362306a36Sopenharmony_ci */ 48462306a36Sopenharmony_ciSTATIC const char * 48562306a36Sopenharmony_cixfs_vn_get_link( 48662306a36Sopenharmony_ci struct dentry *dentry, 48762306a36Sopenharmony_ci struct inode *inode, 48862306a36Sopenharmony_ci struct delayed_call *done) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci char *link; 49162306a36Sopenharmony_ci int error = -ENOMEM; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (!dentry) 49462306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci link = kmalloc(XFS_SYMLINK_MAXLEN+1, GFP_KERNEL); 49762306a36Sopenharmony_ci if (!link) 49862306a36Sopenharmony_ci goto out_err; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci error = xfs_readlink(XFS_I(d_inode(dentry)), link); 50162306a36Sopenharmony_ci if (unlikely(error)) 50262306a36Sopenharmony_ci goto out_kfree; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci set_delayed_call(done, kfree_link, link); 50562306a36Sopenharmony_ci return link; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci out_kfree: 50862306a36Sopenharmony_ci kfree(link); 50962306a36Sopenharmony_ci out_err: 51062306a36Sopenharmony_ci return ERR_PTR(error); 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic uint32_t 51462306a36Sopenharmony_cixfs_stat_blksize( 51562306a36Sopenharmony_ci struct xfs_inode *ip) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci struct xfs_mount *mp = ip->i_mount; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci /* 52062306a36Sopenharmony_ci * If the file blocks are being allocated from a realtime volume, then 52162306a36Sopenharmony_ci * always return the realtime extent size. 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_ci if (XFS_IS_REALTIME_INODE(ip)) 52462306a36Sopenharmony_ci return XFS_FSB_TO_B(mp, xfs_get_extsz_hint(ip)); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci /* 52762306a36Sopenharmony_ci * Allow large block sizes to be reported to userspace programs if the 52862306a36Sopenharmony_ci * "largeio" mount option is used. 52962306a36Sopenharmony_ci * 53062306a36Sopenharmony_ci * If compatibility mode is specified, simply return the basic unit of 53162306a36Sopenharmony_ci * caching so that we don't get inefficient read/modify/write I/O from 53262306a36Sopenharmony_ci * user apps. Otherwise.... 53362306a36Sopenharmony_ci * 53462306a36Sopenharmony_ci * If the underlying volume is a stripe, then return the stripe width in 53562306a36Sopenharmony_ci * bytes as the recommended I/O size. It is not a stripe and we've set a 53662306a36Sopenharmony_ci * default buffered I/O size, return that, otherwise return the compat 53762306a36Sopenharmony_ci * default. 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_ci if (xfs_has_large_iosize(mp)) { 54062306a36Sopenharmony_ci if (mp->m_swidth) 54162306a36Sopenharmony_ci return XFS_FSB_TO_B(mp, mp->m_swidth); 54262306a36Sopenharmony_ci if (xfs_has_allocsize(mp)) 54362306a36Sopenharmony_ci return 1U << mp->m_allocsize_log; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci return PAGE_SIZE; 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ciSTATIC int 55062306a36Sopenharmony_cixfs_vn_getattr( 55162306a36Sopenharmony_ci struct mnt_idmap *idmap, 55262306a36Sopenharmony_ci const struct path *path, 55362306a36Sopenharmony_ci struct kstat *stat, 55462306a36Sopenharmony_ci u32 request_mask, 55562306a36Sopenharmony_ci unsigned int query_flags) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci struct inode *inode = d_inode(path->dentry); 55862306a36Sopenharmony_ci struct xfs_inode *ip = XFS_I(inode); 55962306a36Sopenharmony_ci struct xfs_mount *mp = ip->i_mount; 56062306a36Sopenharmony_ci vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, inode); 56162306a36Sopenharmony_ci vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci trace_xfs_getattr(ip); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (xfs_is_shutdown(mp)) 56662306a36Sopenharmony_ci return -EIO; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci stat->size = XFS_ISIZE(ip); 56962306a36Sopenharmony_ci stat->dev = inode->i_sb->s_dev; 57062306a36Sopenharmony_ci stat->mode = inode->i_mode; 57162306a36Sopenharmony_ci stat->nlink = inode->i_nlink; 57262306a36Sopenharmony_ci stat->uid = vfsuid_into_kuid(vfsuid); 57362306a36Sopenharmony_ci stat->gid = vfsgid_into_kgid(vfsgid); 57462306a36Sopenharmony_ci stat->ino = ip->i_ino; 57562306a36Sopenharmony_ci stat->atime = inode->i_atime; 57662306a36Sopenharmony_ci stat->mtime = inode->i_mtime; 57762306a36Sopenharmony_ci stat->ctime = inode_get_ctime(inode); 57862306a36Sopenharmony_ci stat->blocks = XFS_FSB_TO_BB(mp, ip->i_nblocks + ip->i_delayed_blks); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci if (xfs_has_v3inodes(mp)) { 58162306a36Sopenharmony_ci if (request_mask & STATX_BTIME) { 58262306a36Sopenharmony_ci stat->result_mask |= STATX_BTIME; 58362306a36Sopenharmony_ci stat->btime = ip->i_crtime; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if ((request_mask & STATX_CHANGE_COOKIE) && IS_I_VERSION(inode)) { 58862306a36Sopenharmony_ci stat->change_cookie = inode_query_iversion(inode); 58962306a36Sopenharmony_ci stat->result_mask |= STATX_CHANGE_COOKIE; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci /* 59362306a36Sopenharmony_ci * Note: If you add another clause to set an attribute flag, please 59462306a36Sopenharmony_ci * update attributes_mask below. 59562306a36Sopenharmony_ci */ 59662306a36Sopenharmony_ci if (ip->i_diflags & XFS_DIFLAG_IMMUTABLE) 59762306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_IMMUTABLE; 59862306a36Sopenharmony_ci if (ip->i_diflags & XFS_DIFLAG_APPEND) 59962306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_APPEND; 60062306a36Sopenharmony_ci if (ip->i_diflags & XFS_DIFLAG_NODUMP) 60162306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_NODUMP; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci stat->attributes_mask |= (STATX_ATTR_IMMUTABLE | 60462306a36Sopenharmony_ci STATX_ATTR_APPEND | 60562306a36Sopenharmony_ci STATX_ATTR_NODUMP); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci switch (inode->i_mode & S_IFMT) { 60862306a36Sopenharmony_ci case S_IFBLK: 60962306a36Sopenharmony_ci case S_IFCHR: 61062306a36Sopenharmony_ci stat->blksize = BLKDEV_IOSIZE; 61162306a36Sopenharmony_ci stat->rdev = inode->i_rdev; 61262306a36Sopenharmony_ci break; 61362306a36Sopenharmony_ci case S_IFREG: 61462306a36Sopenharmony_ci if (request_mask & STATX_DIOALIGN) { 61562306a36Sopenharmony_ci struct xfs_buftarg *target = xfs_inode_buftarg(ip); 61662306a36Sopenharmony_ci struct block_device *bdev = target->bt_bdev; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci stat->result_mask |= STATX_DIOALIGN; 61962306a36Sopenharmony_ci stat->dio_mem_align = bdev_dma_alignment(bdev) + 1; 62062306a36Sopenharmony_ci stat->dio_offset_align = bdev_logical_block_size(bdev); 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci fallthrough; 62362306a36Sopenharmony_ci default: 62462306a36Sopenharmony_ci stat->blksize = xfs_stat_blksize(ip); 62562306a36Sopenharmony_ci stat->rdev = 0; 62662306a36Sopenharmony_ci break; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci return 0; 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic int 63362306a36Sopenharmony_cixfs_vn_change_ok( 63462306a36Sopenharmony_ci struct mnt_idmap *idmap, 63562306a36Sopenharmony_ci struct dentry *dentry, 63662306a36Sopenharmony_ci struct iattr *iattr) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci struct xfs_mount *mp = XFS_I(d_inode(dentry))->i_mount; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci if (xfs_is_readonly(mp)) 64162306a36Sopenharmony_ci return -EROFS; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (xfs_is_shutdown(mp)) 64462306a36Sopenharmony_ci return -EIO; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci return setattr_prepare(idmap, dentry, iattr); 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci/* 65062306a36Sopenharmony_ci * Set non-size attributes of an inode. 65162306a36Sopenharmony_ci * 65262306a36Sopenharmony_ci * Caution: The caller of this function is responsible for calling 65362306a36Sopenharmony_ci * setattr_prepare() or otherwise verifying the change is fine. 65462306a36Sopenharmony_ci */ 65562306a36Sopenharmony_cistatic int 65662306a36Sopenharmony_cixfs_setattr_nonsize( 65762306a36Sopenharmony_ci struct mnt_idmap *idmap, 65862306a36Sopenharmony_ci struct dentry *dentry, 65962306a36Sopenharmony_ci struct xfs_inode *ip, 66062306a36Sopenharmony_ci struct iattr *iattr) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci xfs_mount_t *mp = ip->i_mount; 66362306a36Sopenharmony_ci struct inode *inode = VFS_I(ip); 66462306a36Sopenharmony_ci int mask = iattr->ia_valid; 66562306a36Sopenharmony_ci xfs_trans_t *tp; 66662306a36Sopenharmony_ci int error; 66762306a36Sopenharmony_ci kuid_t uid = GLOBAL_ROOT_UID; 66862306a36Sopenharmony_ci kgid_t gid = GLOBAL_ROOT_GID; 66962306a36Sopenharmony_ci struct xfs_dquot *udqp = NULL, *gdqp = NULL; 67062306a36Sopenharmony_ci struct xfs_dquot *old_udqp = NULL, *old_gdqp = NULL; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci ASSERT((mask & ATTR_SIZE) == 0); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* 67562306a36Sopenharmony_ci * If disk quotas is on, we make sure that the dquots do exist on disk, 67662306a36Sopenharmony_ci * before we start any other transactions. Trying to do this later 67762306a36Sopenharmony_ci * is messy. We don't care to take a readlock to look at the ids 67862306a36Sopenharmony_ci * in inode here, because we can't hold it across the trans_reserve. 67962306a36Sopenharmony_ci * If the IDs do change before we take the ilock, we're covered 68062306a36Sopenharmony_ci * because the i_*dquot fields will get updated anyway. 68162306a36Sopenharmony_ci */ 68262306a36Sopenharmony_ci if (XFS_IS_QUOTA_ON(mp) && (mask & (ATTR_UID|ATTR_GID))) { 68362306a36Sopenharmony_ci uint qflags = 0; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if ((mask & ATTR_UID) && XFS_IS_UQUOTA_ON(mp)) { 68662306a36Sopenharmony_ci uid = from_vfsuid(idmap, i_user_ns(inode), 68762306a36Sopenharmony_ci iattr->ia_vfsuid); 68862306a36Sopenharmony_ci qflags |= XFS_QMOPT_UQUOTA; 68962306a36Sopenharmony_ci } else { 69062306a36Sopenharmony_ci uid = inode->i_uid; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci if ((mask & ATTR_GID) && XFS_IS_GQUOTA_ON(mp)) { 69362306a36Sopenharmony_ci gid = from_vfsgid(idmap, i_user_ns(inode), 69462306a36Sopenharmony_ci iattr->ia_vfsgid); 69562306a36Sopenharmony_ci qflags |= XFS_QMOPT_GQUOTA; 69662306a36Sopenharmony_ci } else { 69762306a36Sopenharmony_ci gid = inode->i_gid; 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci /* 70162306a36Sopenharmony_ci * We take a reference when we initialize udqp and gdqp, 70262306a36Sopenharmony_ci * so it is important that we never blindly double trip on 70362306a36Sopenharmony_ci * the same variable. See xfs_create() for an example. 70462306a36Sopenharmony_ci */ 70562306a36Sopenharmony_ci ASSERT(udqp == NULL); 70662306a36Sopenharmony_ci ASSERT(gdqp == NULL); 70762306a36Sopenharmony_ci error = xfs_qm_vop_dqalloc(ip, uid, gid, ip->i_projid, 70862306a36Sopenharmony_ci qflags, &udqp, &gdqp, NULL); 70962306a36Sopenharmony_ci if (error) 71062306a36Sopenharmony_ci return error; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci error = xfs_trans_alloc_ichange(ip, udqp, gdqp, NULL, 71462306a36Sopenharmony_ci has_capability_noaudit(current, CAP_FOWNER), &tp); 71562306a36Sopenharmony_ci if (error) 71662306a36Sopenharmony_ci goto out_dqrele; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci /* 71962306a36Sopenharmony_ci * Register quota modifications in the transaction. Must be the owner 72062306a36Sopenharmony_ci * or privileged. These IDs could have changed since we last looked at 72162306a36Sopenharmony_ci * them. But, we're assured that if the ownership did change while we 72262306a36Sopenharmony_ci * didn't have the inode locked, inode's dquot(s) would have changed 72362306a36Sopenharmony_ci * also. 72462306a36Sopenharmony_ci */ 72562306a36Sopenharmony_ci if (XFS_IS_UQUOTA_ON(mp) && 72662306a36Sopenharmony_ci i_uid_needs_update(idmap, iattr, inode)) { 72762306a36Sopenharmony_ci ASSERT(udqp); 72862306a36Sopenharmony_ci old_udqp = xfs_qm_vop_chown(tp, ip, &ip->i_udquot, udqp); 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci if (XFS_IS_GQUOTA_ON(mp) && 73162306a36Sopenharmony_ci i_gid_needs_update(idmap, iattr, inode)) { 73262306a36Sopenharmony_ci ASSERT(xfs_has_pquotino(mp) || !XFS_IS_PQUOTA_ON(mp)); 73362306a36Sopenharmony_ci ASSERT(gdqp); 73462306a36Sopenharmony_ci old_gdqp = xfs_qm_vop_chown(tp, ip, &ip->i_gdquot, gdqp); 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci setattr_copy(idmap, inode, iattr); 73862306a36Sopenharmony_ci xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci XFS_STATS_INC(mp, xs_ig_attrchg); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (xfs_has_wsync(mp)) 74362306a36Sopenharmony_ci xfs_trans_set_sync(tp); 74462306a36Sopenharmony_ci error = xfs_trans_commit(tp); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci /* 74762306a36Sopenharmony_ci * Release any dquot(s) the inode had kept before chown. 74862306a36Sopenharmony_ci */ 74962306a36Sopenharmony_ci xfs_qm_dqrele(old_udqp); 75062306a36Sopenharmony_ci xfs_qm_dqrele(old_gdqp); 75162306a36Sopenharmony_ci xfs_qm_dqrele(udqp); 75262306a36Sopenharmony_ci xfs_qm_dqrele(gdqp); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci if (error) 75562306a36Sopenharmony_ci return error; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci /* 75862306a36Sopenharmony_ci * XXX(hch): Updating the ACL entries is not atomic vs the i_mode 75962306a36Sopenharmony_ci * update. We could avoid this with linked transactions 76062306a36Sopenharmony_ci * and passing down the transaction pointer all the way 76162306a36Sopenharmony_ci * to attr_set. No previous user of the generic 76262306a36Sopenharmony_ci * Posix ACL code seems to care about this issue either. 76362306a36Sopenharmony_ci */ 76462306a36Sopenharmony_ci if (mask & ATTR_MODE) { 76562306a36Sopenharmony_ci error = posix_acl_chmod(idmap, dentry, inode->i_mode); 76662306a36Sopenharmony_ci if (error) 76762306a36Sopenharmony_ci return error; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci return 0; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ciout_dqrele: 77362306a36Sopenharmony_ci xfs_qm_dqrele(udqp); 77462306a36Sopenharmony_ci xfs_qm_dqrele(gdqp); 77562306a36Sopenharmony_ci return error; 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci/* 77962306a36Sopenharmony_ci * Truncate file. Must have write permission and not be a directory. 78062306a36Sopenharmony_ci * 78162306a36Sopenharmony_ci * Caution: The caller of this function is responsible for calling 78262306a36Sopenharmony_ci * setattr_prepare() or otherwise verifying the change is fine. 78362306a36Sopenharmony_ci */ 78462306a36Sopenharmony_ciSTATIC int 78562306a36Sopenharmony_cixfs_setattr_size( 78662306a36Sopenharmony_ci struct mnt_idmap *idmap, 78762306a36Sopenharmony_ci struct dentry *dentry, 78862306a36Sopenharmony_ci struct xfs_inode *ip, 78962306a36Sopenharmony_ci struct iattr *iattr) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci struct xfs_mount *mp = ip->i_mount; 79262306a36Sopenharmony_ci struct inode *inode = VFS_I(ip); 79362306a36Sopenharmony_ci xfs_off_t oldsize, newsize; 79462306a36Sopenharmony_ci struct xfs_trans *tp; 79562306a36Sopenharmony_ci int error; 79662306a36Sopenharmony_ci uint lock_flags = 0; 79762306a36Sopenharmony_ci bool did_zeroing = false; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); 80062306a36Sopenharmony_ci ASSERT(xfs_isilocked(ip, XFS_MMAPLOCK_EXCL)); 80162306a36Sopenharmony_ci ASSERT(S_ISREG(inode->i_mode)); 80262306a36Sopenharmony_ci ASSERT((iattr->ia_valid & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET| 80362306a36Sopenharmony_ci ATTR_MTIME_SET|ATTR_TIMES_SET)) == 0); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci oldsize = inode->i_size; 80662306a36Sopenharmony_ci newsize = iattr->ia_size; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci /* 80962306a36Sopenharmony_ci * Short circuit the truncate case for zero length files. 81062306a36Sopenharmony_ci */ 81162306a36Sopenharmony_ci if (newsize == 0 && oldsize == 0 && ip->i_df.if_nextents == 0) { 81262306a36Sopenharmony_ci if (!(iattr->ia_valid & (ATTR_CTIME|ATTR_MTIME))) 81362306a36Sopenharmony_ci return 0; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci /* 81662306a36Sopenharmony_ci * Use the regular setattr path to update the timestamps. 81762306a36Sopenharmony_ci */ 81862306a36Sopenharmony_ci iattr->ia_valid &= ~ATTR_SIZE; 81962306a36Sopenharmony_ci return xfs_setattr_nonsize(idmap, dentry, ip, iattr); 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci /* 82362306a36Sopenharmony_ci * Make sure that the dquots are attached to the inode. 82462306a36Sopenharmony_ci */ 82562306a36Sopenharmony_ci error = xfs_qm_dqattach(ip); 82662306a36Sopenharmony_ci if (error) 82762306a36Sopenharmony_ci return error; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci /* 83062306a36Sopenharmony_ci * Wait for all direct I/O to complete. 83162306a36Sopenharmony_ci */ 83262306a36Sopenharmony_ci inode_dio_wait(inode); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci /* 83562306a36Sopenharmony_ci * File data changes must be complete before we start the transaction to 83662306a36Sopenharmony_ci * modify the inode. This needs to be done before joining the inode to 83762306a36Sopenharmony_ci * the transaction because the inode cannot be unlocked once it is a 83862306a36Sopenharmony_ci * part of the transaction. 83962306a36Sopenharmony_ci * 84062306a36Sopenharmony_ci * Start with zeroing any data beyond EOF that we may expose on file 84162306a36Sopenharmony_ci * extension, or zeroing out the rest of the block on a downward 84262306a36Sopenharmony_ci * truncate. 84362306a36Sopenharmony_ci */ 84462306a36Sopenharmony_ci if (newsize > oldsize) { 84562306a36Sopenharmony_ci trace_xfs_zero_eof(ip, oldsize, newsize - oldsize); 84662306a36Sopenharmony_ci error = xfs_zero_range(ip, oldsize, newsize - oldsize, 84762306a36Sopenharmony_ci &did_zeroing); 84862306a36Sopenharmony_ci } else { 84962306a36Sopenharmony_ci /* 85062306a36Sopenharmony_ci * iomap won't detect a dirty page over an unwritten block (or a 85162306a36Sopenharmony_ci * cow block over a hole) and subsequently skips zeroing the 85262306a36Sopenharmony_ci * newly post-EOF portion of the page. Flush the new EOF to 85362306a36Sopenharmony_ci * convert the block before the pagecache truncate. 85462306a36Sopenharmony_ci */ 85562306a36Sopenharmony_ci error = filemap_write_and_wait_range(inode->i_mapping, newsize, 85662306a36Sopenharmony_ci newsize); 85762306a36Sopenharmony_ci if (error) 85862306a36Sopenharmony_ci return error; 85962306a36Sopenharmony_ci error = xfs_truncate_page(ip, newsize, &did_zeroing); 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci if (error) 86362306a36Sopenharmony_ci return error; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci /* 86662306a36Sopenharmony_ci * We've already locked out new page faults, so now we can safely remove 86762306a36Sopenharmony_ci * pages from the page cache knowing they won't get refaulted until we 86862306a36Sopenharmony_ci * drop the XFS_MMAP_EXCL lock after the extent manipulations are 86962306a36Sopenharmony_ci * complete. The truncate_setsize() call also cleans partial EOF page 87062306a36Sopenharmony_ci * PTEs on extending truncates and hence ensures sub-page block size 87162306a36Sopenharmony_ci * filesystems are correctly handled, too. 87262306a36Sopenharmony_ci * 87362306a36Sopenharmony_ci * We have to do all the page cache truncate work outside the 87462306a36Sopenharmony_ci * transaction context as the "lock" order is page lock->log space 87562306a36Sopenharmony_ci * reservation as defined by extent allocation in the writeback path. 87662306a36Sopenharmony_ci * Hence a truncate can fail with ENOMEM from xfs_trans_alloc(), but 87762306a36Sopenharmony_ci * having already truncated the in-memory version of the file (i.e. made 87862306a36Sopenharmony_ci * user visible changes). There's not much we can do about this, except 87962306a36Sopenharmony_ci * to hope that the caller sees ENOMEM and retries the truncate 88062306a36Sopenharmony_ci * operation. 88162306a36Sopenharmony_ci * 88262306a36Sopenharmony_ci * And we update in-core i_size and truncate page cache beyond newsize 88362306a36Sopenharmony_ci * before writeback the [i_disk_size, newsize] range, so we're 88462306a36Sopenharmony_ci * guaranteed not to write stale data past the new EOF on truncate down. 88562306a36Sopenharmony_ci */ 88662306a36Sopenharmony_ci truncate_setsize(inode, newsize); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci /* 88962306a36Sopenharmony_ci * We are going to log the inode size change in this transaction so 89062306a36Sopenharmony_ci * any previous writes that are beyond the on disk EOF and the new 89162306a36Sopenharmony_ci * EOF that have not been written out need to be written here. If we 89262306a36Sopenharmony_ci * do not write the data out, we expose ourselves to the null files 89362306a36Sopenharmony_ci * problem. Note that this includes any block zeroing we did above; 89462306a36Sopenharmony_ci * otherwise those blocks may not be zeroed after a crash. 89562306a36Sopenharmony_ci */ 89662306a36Sopenharmony_ci if (did_zeroing || 89762306a36Sopenharmony_ci (newsize > ip->i_disk_size && oldsize != ip->i_disk_size)) { 89862306a36Sopenharmony_ci error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping, 89962306a36Sopenharmony_ci ip->i_disk_size, newsize - 1); 90062306a36Sopenharmony_ci if (error) 90162306a36Sopenharmony_ci return error; 90262306a36Sopenharmony_ci } 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp); 90562306a36Sopenharmony_ci if (error) 90662306a36Sopenharmony_ci return error; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci lock_flags |= XFS_ILOCK_EXCL; 90962306a36Sopenharmony_ci xfs_ilock(ip, XFS_ILOCK_EXCL); 91062306a36Sopenharmony_ci xfs_trans_ijoin(tp, ip, 0); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci /* 91362306a36Sopenharmony_ci * Only change the c/mtime if we are changing the size or we are 91462306a36Sopenharmony_ci * explicitly asked to change it. This handles the semantic difference 91562306a36Sopenharmony_ci * between truncate() and ftruncate() as implemented in the VFS. 91662306a36Sopenharmony_ci * 91762306a36Sopenharmony_ci * The regular truncate() case without ATTR_CTIME and ATTR_MTIME is a 91862306a36Sopenharmony_ci * special case where we need to update the times despite not having 91962306a36Sopenharmony_ci * these flags set. For all other operations the VFS set these flags 92062306a36Sopenharmony_ci * explicitly if it wants a timestamp update. 92162306a36Sopenharmony_ci */ 92262306a36Sopenharmony_ci if (newsize != oldsize && 92362306a36Sopenharmony_ci !(iattr->ia_valid & (ATTR_CTIME | ATTR_MTIME))) { 92462306a36Sopenharmony_ci iattr->ia_ctime = iattr->ia_mtime = 92562306a36Sopenharmony_ci current_time(inode); 92662306a36Sopenharmony_ci iattr->ia_valid |= ATTR_CTIME | ATTR_MTIME; 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci /* 93062306a36Sopenharmony_ci * The first thing we do is set the size to new_size permanently on 93162306a36Sopenharmony_ci * disk. This way we don't have to worry about anyone ever being able 93262306a36Sopenharmony_ci * to look at the data being freed even in the face of a crash. 93362306a36Sopenharmony_ci * What we're getting around here is the case where we free a block, it 93462306a36Sopenharmony_ci * is allocated to another file, it is written to, and then we crash. 93562306a36Sopenharmony_ci * If the new data gets written to the file but the log buffers 93662306a36Sopenharmony_ci * containing the free and reallocation don't, then we'd end up with 93762306a36Sopenharmony_ci * garbage in the blocks being freed. As long as we make the new size 93862306a36Sopenharmony_ci * permanent before actually freeing any blocks it doesn't matter if 93962306a36Sopenharmony_ci * they get written to. 94062306a36Sopenharmony_ci */ 94162306a36Sopenharmony_ci ip->i_disk_size = newsize; 94262306a36Sopenharmony_ci xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci if (newsize <= oldsize) { 94562306a36Sopenharmony_ci error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, newsize); 94662306a36Sopenharmony_ci if (error) 94762306a36Sopenharmony_ci goto out_trans_cancel; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci /* 95062306a36Sopenharmony_ci * Truncated "down", so we're removing references to old data 95162306a36Sopenharmony_ci * here - if we delay flushing for a long time, we expose 95262306a36Sopenharmony_ci * ourselves unduly to the notorious NULL files problem. So, 95362306a36Sopenharmony_ci * we mark this inode and flush it when the file is closed, 95462306a36Sopenharmony_ci * and do not wait the usual (long) time for writeout. 95562306a36Sopenharmony_ci */ 95662306a36Sopenharmony_ci xfs_iflags_set(ip, XFS_ITRUNCATED); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci /* A truncate down always removes post-EOF blocks. */ 95962306a36Sopenharmony_ci xfs_inode_clear_eofblocks_tag(ip); 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci ASSERT(!(iattr->ia_valid & (ATTR_UID | ATTR_GID))); 96362306a36Sopenharmony_ci setattr_copy(idmap, inode, iattr); 96462306a36Sopenharmony_ci xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci XFS_STATS_INC(mp, xs_ig_attrchg); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci if (xfs_has_wsync(mp)) 96962306a36Sopenharmony_ci xfs_trans_set_sync(tp); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci error = xfs_trans_commit(tp); 97262306a36Sopenharmony_ciout_unlock: 97362306a36Sopenharmony_ci if (lock_flags) 97462306a36Sopenharmony_ci xfs_iunlock(ip, lock_flags); 97562306a36Sopenharmony_ci return error; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ciout_trans_cancel: 97862306a36Sopenharmony_ci xfs_trans_cancel(tp); 97962306a36Sopenharmony_ci goto out_unlock; 98062306a36Sopenharmony_ci} 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ciint 98362306a36Sopenharmony_cixfs_vn_setattr_size( 98462306a36Sopenharmony_ci struct mnt_idmap *idmap, 98562306a36Sopenharmony_ci struct dentry *dentry, 98662306a36Sopenharmony_ci struct iattr *iattr) 98762306a36Sopenharmony_ci{ 98862306a36Sopenharmony_ci struct xfs_inode *ip = XFS_I(d_inode(dentry)); 98962306a36Sopenharmony_ci int error; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci trace_xfs_setattr(ip); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci error = xfs_vn_change_ok(idmap, dentry, iattr); 99462306a36Sopenharmony_ci if (error) 99562306a36Sopenharmony_ci return error; 99662306a36Sopenharmony_ci return xfs_setattr_size(idmap, dentry, ip, iattr); 99762306a36Sopenharmony_ci} 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ciSTATIC int 100062306a36Sopenharmony_cixfs_vn_setattr( 100162306a36Sopenharmony_ci struct mnt_idmap *idmap, 100262306a36Sopenharmony_ci struct dentry *dentry, 100362306a36Sopenharmony_ci struct iattr *iattr) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 100662306a36Sopenharmony_ci struct xfs_inode *ip = XFS_I(inode); 100762306a36Sopenharmony_ci int error; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (iattr->ia_valid & ATTR_SIZE) { 101062306a36Sopenharmony_ci uint iolock; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci xfs_ilock(ip, XFS_MMAPLOCK_EXCL); 101362306a36Sopenharmony_ci iolock = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci error = xfs_break_layouts(inode, &iolock, BREAK_UNMAP); 101662306a36Sopenharmony_ci if (error) { 101762306a36Sopenharmony_ci xfs_iunlock(ip, XFS_MMAPLOCK_EXCL); 101862306a36Sopenharmony_ci return error; 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci error = xfs_vn_setattr_size(idmap, dentry, iattr); 102262306a36Sopenharmony_ci xfs_iunlock(ip, XFS_MMAPLOCK_EXCL); 102362306a36Sopenharmony_ci } else { 102462306a36Sopenharmony_ci trace_xfs_setattr(ip); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci error = xfs_vn_change_ok(idmap, dentry, iattr); 102762306a36Sopenharmony_ci if (!error) 102862306a36Sopenharmony_ci error = xfs_setattr_nonsize(idmap, dentry, ip, iattr); 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci return error; 103262306a36Sopenharmony_ci} 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ciSTATIC int 103562306a36Sopenharmony_cixfs_vn_update_time( 103662306a36Sopenharmony_ci struct inode *inode, 103762306a36Sopenharmony_ci int flags) 103862306a36Sopenharmony_ci{ 103962306a36Sopenharmony_ci struct xfs_inode *ip = XFS_I(inode); 104062306a36Sopenharmony_ci struct xfs_mount *mp = ip->i_mount; 104162306a36Sopenharmony_ci int log_flags = XFS_ILOG_TIMESTAMP; 104262306a36Sopenharmony_ci struct xfs_trans *tp; 104362306a36Sopenharmony_ci int error; 104462306a36Sopenharmony_ci struct timespec64 now; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci trace_xfs_update_time(ip); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci if (inode->i_sb->s_flags & SB_LAZYTIME) { 104962306a36Sopenharmony_ci if (!((flags & S_VERSION) && 105062306a36Sopenharmony_ci inode_maybe_inc_iversion(inode, false))) { 105162306a36Sopenharmony_ci generic_update_time(inode, flags); 105262306a36Sopenharmony_ci return 0; 105362306a36Sopenharmony_ci } 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci /* Capture the iversion update that just occurred */ 105662306a36Sopenharmony_ci log_flags |= XFS_ILOG_CORE; 105762306a36Sopenharmony_ci } 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci error = xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp); 106062306a36Sopenharmony_ci if (error) 106162306a36Sopenharmony_ci return error; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci xfs_ilock(ip, XFS_ILOCK_EXCL); 106462306a36Sopenharmony_ci if (flags & (S_CTIME|S_MTIME)) 106562306a36Sopenharmony_ci now = inode_set_ctime_current(inode); 106662306a36Sopenharmony_ci else 106762306a36Sopenharmony_ci now = current_time(inode); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if (flags & S_MTIME) 107062306a36Sopenharmony_ci inode->i_mtime = now; 107162306a36Sopenharmony_ci if (flags & S_ATIME) 107262306a36Sopenharmony_ci inode->i_atime = now; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); 107562306a36Sopenharmony_ci xfs_trans_log_inode(tp, ip, log_flags); 107662306a36Sopenharmony_ci return xfs_trans_commit(tp); 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ciSTATIC int 108062306a36Sopenharmony_cixfs_vn_fiemap( 108162306a36Sopenharmony_ci struct inode *inode, 108262306a36Sopenharmony_ci struct fiemap_extent_info *fieinfo, 108362306a36Sopenharmony_ci u64 start, 108462306a36Sopenharmony_ci u64 length) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci int error; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci xfs_ilock(XFS_I(inode), XFS_IOLOCK_SHARED); 108962306a36Sopenharmony_ci if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) { 109062306a36Sopenharmony_ci fieinfo->fi_flags &= ~FIEMAP_FLAG_XATTR; 109162306a36Sopenharmony_ci error = iomap_fiemap(inode, fieinfo, start, length, 109262306a36Sopenharmony_ci &xfs_xattr_iomap_ops); 109362306a36Sopenharmony_ci } else { 109462306a36Sopenharmony_ci error = iomap_fiemap(inode, fieinfo, start, length, 109562306a36Sopenharmony_ci &xfs_read_iomap_ops); 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci xfs_iunlock(XFS_I(inode), XFS_IOLOCK_SHARED); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci return error; 110062306a36Sopenharmony_ci} 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ciSTATIC int 110362306a36Sopenharmony_cixfs_vn_tmpfile( 110462306a36Sopenharmony_ci struct mnt_idmap *idmap, 110562306a36Sopenharmony_ci struct inode *dir, 110662306a36Sopenharmony_ci struct file *file, 110762306a36Sopenharmony_ci umode_t mode) 110862306a36Sopenharmony_ci{ 110962306a36Sopenharmony_ci int err = xfs_generic_create(idmap, dir, file->f_path.dentry, mode, 0, file); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci return finish_open_simple(file, err); 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_cistatic const struct inode_operations xfs_inode_operations = { 111562306a36Sopenharmony_ci .get_inode_acl = xfs_get_acl, 111662306a36Sopenharmony_ci .set_acl = xfs_set_acl, 111762306a36Sopenharmony_ci .getattr = xfs_vn_getattr, 111862306a36Sopenharmony_ci .setattr = xfs_vn_setattr, 111962306a36Sopenharmony_ci .listxattr = xfs_vn_listxattr, 112062306a36Sopenharmony_ci .fiemap = xfs_vn_fiemap, 112162306a36Sopenharmony_ci .update_time = xfs_vn_update_time, 112262306a36Sopenharmony_ci .fileattr_get = xfs_fileattr_get, 112362306a36Sopenharmony_ci .fileattr_set = xfs_fileattr_set, 112462306a36Sopenharmony_ci}; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_cistatic const struct inode_operations xfs_dir_inode_operations = { 112762306a36Sopenharmony_ci .create = xfs_vn_create, 112862306a36Sopenharmony_ci .lookup = xfs_vn_lookup, 112962306a36Sopenharmony_ci .link = xfs_vn_link, 113062306a36Sopenharmony_ci .unlink = xfs_vn_unlink, 113162306a36Sopenharmony_ci .symlink = xfs_vn_symlink, 113262306a36Sopenharmony_ci .mkdir = xfs_vn_mkdir, 113362306a36Sopenharmony_ci /* 113462306a36Sopenharmony_ci * Yes, XFS uses the same method for rmdir and unlink. 113562306a36Sopenharmony_ci * 113662306a36Sopenharmony_ci * There are some subtile differences deeper in the code, 113762306a36Sopenharmony_ci * but we use S_ISDIR to check for those. 113862306a36Sopenharmony_ci */ 113962306a36Sopenharmony_ci .rmdir = xfs_vn_unlink, 114062306a36Sopenharmony_ci .mknod = xfs_vn_mknod, 114162306a36Sopenharmony_ci .rename = xfs_vn_rename, 114262306a36Sopenharmony_ci .get_inode_acl = xfs_get_acl, 114362306a36Sopenharmony_ci .set_acl = xfs_set_acl, 114462306a36Sopenharmony_ci .getattr = xfs_vn_getattr, 114562306a36Sopenharmony_ci .setattr = xfs_vn_setattr, 114662306a36Sopenharmony_ci .listxattr = xfs_vn_listxattr, 114762306a36Sopenharmony_ci .update_time = xfs_vn_update_time, 114862306a36Sopenharmony_ci .tmpfile = xfs_vn_tmpfile, 114962306a36Sopenharmony_ci .fileattr_get = xfs_fileattr_get, 115062306a36Sopenharmony_ci .fileattr_set = xfs_fileattr_set, 115162306a36Sopenharmony_ci}; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_cistatic const struct inode_operations xfs_dir_ci_inode_operations = { 115462306a36Sopenharmony_ci .create = xfs_vn_create, 115562306a36Sopenharmony_ci .lookup = xfs_vn_ci_lookup, 115662306a36Sopenharmony_ci .link = xfs_vn_link, 115762306a36Sopenharmony_ci .unlink = xfs_vn_unlink, 115862306a36Sopenharmony_ci .symlink = xfs_vn_symlink, 115962306a36Sopenharmony_ci .mkdir = xfs_vn_mkdir, 116062306a36Sopenharmony_ci /* 116162306a36Sopenharmony_ci * Yes, XFS uses the same method for rmdir and unlink. 116262306a36Sopenharmony_ci * 116362306a36Sopenharmony_ci * There are some subtile differences deeper in the code, 116462306a36Sopenharmony_ci * but we use S_ISDIR to check for those. 116562306a36Sopenharmony_ci */ 116662306a36Sopenharmony_ci .rmdir = xfs_vn_unlink, 116762306a36Sopenharmony_ci .mknod = xfs_vn_mknod, 116862306a36Sopenharmony_ci .rename = xfs_vn_rename, 116962306a36Sopenharmony_ci .get_inode_acl = xfs_get_acl, 117062306a36Sopenharmony_ci .set_acl = xfs_set_acl, 117162306a36Sopenharmony_ci .getattr = xfs_vn_getattr, 117262306a36Sopenharmony_ci .setattr = xfs_vn_setattr, 117362306a36Sopenharmony_ci .listxattr = xfs_vn_listxattr, 117462306a36Sopenharmony_ci .update_time = xfs_vn_update_time, 117562306a36Sopenharmony_ci .tmpfile = xfs_vn_tmpfile, 117662306a36Sopenharmony_ci .fileattr_get = xfs_fileattr_get, 117762306a36Sopenharmony_ci .fileattr_set = xfs_fileattr_set, 117862306a36Sopenharmony_ci}; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_cistatic const struct inode_operations xfs_symlink_inode_operations = { 118162306a36Sopenharmony_ci .get_link = xfs_vn_get_link, 118262306a36Sopenharmony_ci .getattr = xfs_vn_getattr, 118362306a36Sopenharmony_ci .setattr = xfs_vn_setattr, 118462306a36Sopenharmony_ci .listxattr = xfs_vn_listxattr, 118562306a36Sopenharmony_ci .update_time = xfs_vn_update_time, 118662306a36Sopenharmony_ci}; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci/* Figure out if this file actually supports DAX. */ 118962306a36Sopenharmony_cistatic bool 119062306a36Sopenharmony_cixfs_inode_supports_dax( 119162306a36Sopenharmony_ci struct xfs_inode *ip) 119262306a36Sopenharmony_ci{ 119362306a36Sopenharmony_ci struct xfs_mount *mp = ip->i_mount; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci /* Only supported on regular files. */ 119662306a36Sopenharmony_ci if (!S_ISREG(VFS_I(ip)->i_mode)) 119762306a36Sopenharmony_ci return false; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci /* Block size must match page size */ 120062306a36Sopenharmony_ci if (mp->m_sb.sb_blocksize != PAGE_SIZE) 120162306a36Sopenharmony_ci return false; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci /* Device has to support DAX too. */ 120462306a36Sopenharmony_ci return xfs_inode_buftarg(ip)->bt_daxdev != NULL; 120562306a36Sopenharmony_ci} 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_cistatic bool 120862306a36Sopenharmony_cixfs_inode_should_enable_dax( 120962306a36Sopenharmony_ci struct xfs_inode *ip) 121062306a36Sopenharmony_ci{ 121162306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_FS_DAX)) 121262306a36Sopenharmony_ci return false; 121362306a36Sopenharmony_ci if (xfs_has_dax_never(ip->i_mount)) 121462306a36Sopenharmony_ci return false; 121562306a36Sopenharmony_ci if (!xfs_inode_supports_dax(ip)) 121662306a36Sopenharmony_ci return false; 121762306a36Sopenharmony_ci if (xfs_has_dax_always(ip->i_mount)) 121862306a36Sopenharmony_ci return true; 121962306a36Sopenharmony_ci if (ip->i_diflags2 & XFS_DIFLAG2_DAX) 122062306a36Sopenharmony_ci return true; 122162306a36Sopenharmony_ci return false; 122262306a36Sopenharmony_ci} 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_civoid 122562306a36Sopenharmony_cixfs_diflags_to_iflags( 122662306a36Sopenharmony_ci struct xfs_inode *ip, 122762306a36Sopenharmony_ci bool init) 122862306a36Sopenharmony_ci{ 122962306a36Sopenharmony_ci struct inode *inode = VFS_I(ip); 123062306a36Sopenharmony_ci unsigned int xflags = xfs_ip2xflags(ip); 123162306a36Sopenharmony_ci unsigned int flags = 0; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci ASSERT(!(IS_DAX(inode) && init)); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci if (xflags & FS_XFLAG_IMMUTABLE) 123662306a36Sopenharmony_ci flags |= S_IMMUTABLE; 123762306a36Sopenharmony_ci if (xflags & FS_XFLAG_APPEND) 123862306a36Sopenharmony_ci flags |= S_APPEND; 123962306a36Sopenharmony_ci if (xflags & FS_XFLAG_SYNC) 124062306a36Sopenharmony_ci flags |= S_SYNC; 124162306a36Sopenharmony_ci if (xflags & FS_XFLAG_NOATIME) 124262306a36Sopenharmony_ci flags |= S_NOATIME; 124362306a36Sopenharmony_ci if (init && xfs_inode_should_enable_dax(ip)) 124462306a36Sopenharmony_ci flags |= S_DAX; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci /* 124762306a36Sopenharmony_ci * S_DAX can only be set during inode initialization and is never set by 124862306a36Sopenharmony_ci * the VFS, so we cannot mask off S_DAX in i_flags. 124962306a36Sopenharmony_ci */ 125062306a36Sopenharmony_ci inode->i_flags &= ~(S_IMMUTABLE | S_APPEND | S_SYNC | S_NOATIME); 125162306a36Sopenharmony_ci inode->i_flags |= flags; 125262306a36Sopenharmony_ci} 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci/* 125562306a36Sopenharmony_ci * Initialize the Linux inode. 125662306a36Sopenharmony_ci * 125762306a36Sopenharmony_ci * When reading existing inodes from disk this is called directly from xfs_iget, 125862306a36Sopenharmony_ci * when creating a new inode it is called from xfs_init_new_inode after setting 125962306a36Sopenharmony_ci * up the inode. These callers have different criteria for clearing XFS_INEW, so 126062306a36Sopenharmony_ci * leave it up to the caller to deal with unlocking the inode appropriately. 126162306a36Sopenharmony_ci */ 126262306a36Sopenharmony_civoid 126362306a36Sopenharmony_cixfs_setup_inode( 126462306a36Sopenharmony_ci struct xfs_inode *ip) 126562306a36Sopenharmony_ci{ 126662306a36Sopenharmony_ci struct inode *inode = &ip->i_vnode; 126762306a36Sopenharmony_ci gfp_t gfp_mask; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci inode->i_ino = ip->i_ino; 127062306a36Sopenharmony_ci inode->i_state |= I_NEW; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci inode_sb_list_add(inode); 127362306a36Sopenharmony_ci /* make the inode look hashed for the writeback code */ 127462306a36Sopenharmony_ci inode_fake_hash(inode); 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci i_size_write(inode, ip->i_disk_size); 127762306a36Sopenharmony_ci xfs_diflags_to_iflags(ip, true); 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci if (S_ISDIR(inode->i_mode)) { 128062306a36Sopenharmony_ci /* 128162306a36Sopenharmony_ci * We set the i_rwsem class here to avoid potential races with 128262306a36Sopenharmony_ci * lockdep_annotate_inode_mutex_key() reinitialising the lock 128362306a36Sopenharmony_ci * after a filehandle lookup has already found the inode in 128462306a36Sopenharmony_ci * cache before it has been unlocked via unlock_new_inode(). 128562306a36Sopenharmony_ci */ 128662306a36Sopenharmony_ci lockdep_set_class(&inode->i_rwsem, 128762306a36Sopenharmony_ci &inode->i_sb->s_type->i_mutex_dir_key); 128862306a36Sopenharmony_ci lockdep_set_class(&ip->i_lock.mr_lock, &xfs_dir_ilock_class); 128962306a36Sopenharmony_ci } else { 129062306a36Sopenharmony_ci lockdep_set_class(&ip->i_lock.mr_lock, &xfs_nondir_ilock_class); 129162306a36Sopenharmony_ci } 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci /* 129462306a36Sopenharmony_ci * Ensure all page cache allocations are done from GFP_NOFS context to 129562306a36Sopenharmony_ci * prevent direct reclaim recursion back into the filesystem and blowing 129662306a36Sopenharmony_ci * stacks or deadlocking. 129762306a36Sopenharmony_ci */ 129862306a36Sopenharmony_ci gfp_mask = mapping_gfp_mask(inode->i_mapping); 129962306a36Sopenharmony_ci mapping_set_gfp_mask(inode->i_mapping, (gfp_mask & ~(__GFP_FS))); 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci /* 130262306a36Sopenharmony_ci * For real-time inodes update the stable write flags to that of the RT 130362306a36Sopenharmony_ci * device instead of the data device. 130462306a36Sopenharmony_ci */ 130562306a36Sopenharmony_ci if (S_ISREG(inode->i_mode) && XFS_IS_REALTIME_INODE(ip)) 130662306a36Sopenharmony_ci xfs_update_stable_writes(ip); 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci /* 130962306a36Sopenharmony_ci * If there is no attribute fork no ACL can exist on this inode, 131062306a36Sopenharmony_ci * and it can't have any file capabilities attached to it either. 131162306a36Sopenharmony_ci */ 131262306a36Sopenharmony_ci if (!xfs_inode_has_attr_fork(ip)) { 131362306a36Sopenharmony_ci inode_has_no_xattr(inode); 131462306a36Sopenharmony_ci cache_no_acl(inode); 131562306a36Sopenharmony_ci } 131662306a36Sopenharmony_ci} 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_civoid 131962306a36Sopenharmony_cixfs_setup_iops( 132062306a36Sopenharmony_ci struct xfs_inode *ip) 132162306a36Sopenharmony_ci{ 132262306a36Sopenharmony_ci struct inode *inode = &ip->i_vnode; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci switch (inode->i_mode & S_IFMT) { 132562306a36Sopenharmony_ci case S_IFREG: 132662306a36Sopenharmony_ci inode->i_op = &xfs_inode_operations; 132762306a36Sopenharmony_ci inode->i_fop = &xfs_file_operations; 132862306a36Sopenharmony_ci if (IS_DAX(inode)) 132962306a36Sopenharmony_ci inode->i_mapping->a_ops = &xfs_dax_aops; 133062306a36Sopenharmony_ci else 133162306a36Sopenharmony_ci inode->i_mapping->a_ops = &xfs_address_space_operations; 133262306a36Sopenharmony_ci break; 133362306a36Sopenharmony_ci case S_IFDIR: 133462306a36Sopenharmony_ci if (xfs_has_asciici(XFS_M(inode->i_sb))) 133562306a36Sopenharmony_ci inode->i_op = &xfs_dir_ci_inode_operations; 133662306a36Sopenharmony_ci else 133762306a36Sopenharmony_ci inode->i_op = &xfs_dir_inode_operations; 133862306a36Sopenharmony_ci inode->i_fop = &xfs_dir_file_operations; 133962306a36Sopenharmony_ci break; 134062306a36Sopenharmony_ci case S_IFLNK: 134162306a36Sopenharmony_ci inode->i_op = &xfs_symlink_inode_operations; 134262306a36Sopenharmony_ci break; 134362306a36Sopenharmony_ci default: 134462306a36Sopenharmony_ci inode->i_op = &xfs_inode_operations; 134562306a36Sopenharmony_ci init_special_inode(inode, inode->i_mode, inode->i_rdev); 134662306a36Sopenharmony_ci break; 134762306a36Sopenharmony_ci } 134862306a36Sopenharmony_ci} 1349