1e5e5558eSMiklos Szeredi /* 2e5e5558eSMiklos Szeredi FUSE: Filesystem in Userspace 31729a16cSMiklos Szeredi Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu> 4e5e5558eSMiklos Szeredi 5e5e5558eSMiklos Szeredi This program can be distributed under the terms of the GNU GPL. 6e5e5558eSMiklos Szeredi See the file COPYING. 7e5e5558eSMiklos Szeredi */ 8e5e5558eSMiklos Szeredi 9e5e5558eSMiklos Szeredi #include "fuse_i.h" 10e5e5558eSMiklos Szeredi 11e5e5558eSMiklos Szeredi #include <linux/pagemap.h> 12e5e5558eSMiklos Szeredi #include <linux/file.h> 13bf109c64SMax Reitz #include <linux/fs_context.h> 149ccf47b2SDave Marchevsky #include <linux/moduleparam.h> 15e5e5558eSMiklos Szeredi #include <linux/sched.h> 16e5e5558eSMiklos Szeredi #include <linux/namei.h> 1707e77dcaSMiklos Szeredi #include <linux/slab.h> 18703c7362SSeth Forshee #include <linux/xattr.h> 19261aaba7SMiklos Szeredi #include <linux/iversion.h> 2060bcc88aSSeth Forshee #include <linux/posix_acl.h> 213e2b6fdbSVivek Goyal #include <linux/security.h> 223e2b6fdbSVivek Goyal #include <linux/types.h> 233e2b6fdbSVivek Goyal #include <linux/kernel.h> 24e5e5558eSMiklos Szeredi 259ccf47b2SDave Marchevsky static bool __read_mostly allow_sys_admin_access; 269ccf47b2SDave Marchevsky module_param(allow_sys_admin_access, bool, 0644); 279ccf47b2SDave Marchevsky MODULE_PARM_DESC(allow_sys_admin_access, 289ccf47b2SDave Marchevsky "Allow users with CAP_SYS_ADMIN in initial userns to bypass allow_other access check"); 299ccf47b2SDave Marchevsky 304582a4abSFeng Shuo static void fuse_advise_use_readdirplus(struct inode *dir) 314582a4abSFeng Shuo { 324582a4abSFeng Shuo struct fuse_inode *fi = get_fuse_inode(dir); 334582a4abSFeng Shuo 344582a4abSFeng Shuo set_bit(FUSE_I_ADVISE_RDPLUS, &fi->state); 354582a4abSFeng Shuo } 364582a4abSFeng Shuo 3730c6a23dSKhazhismel Kumykov #if BITS_PER_LONG >= 64 3830c6a23dSKhazhismel Kumykov static inline void __fuse_dentry_settime(struct dentry *entry, u64 time) 3930c6a23dSKhazhismel Kumykov { 4030c6a23dSKhazhismel Kumykov entry->d_fsdata = (void *) time; 4130c6a23dSKhazhismel Kumykov } 4230c6a23dSKhazhismel Kumykov 4330c6a23dSKhazhismel Kumykov static inline u64 fuse_dentry_time(const struct dentry *entry) 4430c6a23dSKhazhismel Kumykov { 4530c6a23dSKhazhismel Kumykov return (u64)entry->d_fsdata; 4630c6a23dSKhazhismel Kumykov } 4730c6a23dSKhazhismel Kumykov 4830c6a23dSKhazhismel Kumykov #else 49f75fdf22SMiklos Szeredi union fuse_dentry { 50f75fdf22SMiklos Szeredi u64 time; 51f75fdf22SMiklos Szeredi struct rcu_head rcu; 52f75fdf22SMiklos Szeredi }; 53f75fdf22SMiklos Szeredi 5430c6a23dSKhazhismel Kumykov static inline void __fuse_dentry_settime(struct dentry *dentry, u64 time) 5530c6a23dSKhazhismel Kumykov { 5630c6a23dSKhazhismel Kumykov ((union fuse_dentry *) dentry->d_fsdata)->time = time; 5730c6a23dSKhazhismel Kumykov } 5830c6a23dSKhazhismel Kumykov 5930c6a23dSKhazhismel Kumykov static inline u64 fuse_dentry_time(const struct dentry *entry) 6030c6a23dSKhazhismel Kumykov { 6130c6a23dSKhazhismel Kumykov return ((union fuse_dentry *) entry->d_fsdata)->time; 6230c6a23dSKhazhismel Kumykov } 6330c6a23dSKhazhismel Kumykov #endif 6430c6a23dSKhazhismel Kumykov 658fab0106SMiklos Szeredi static void fuse_dentry_settime(struct dentry *dentry, u64 time) 660a0898cfSMiklos Szeredi { 678fab0106SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(dentry->d_sb); 688fab0106SMiklos Szeredi bool delete = !time && fc->delete_stale; 698fab0106SMiklos Szeredi /* 708fab0106SMiklos Szeredi * Mess with DCACHE_OP_DELETE because dput() will be faster without it. 718fab0106SMiklos Szeredi * Don't care about races, either way it's just an optimization 728fab0106SMiklos Szeredi */ 738fab0106SMiklos Szeredi if ((!delete && (dentry->d_flags & DCACHE_OP_DELETE)) || 748fab0106SMiklos Szeredi (delete && !(dentry->d_flags & DCACHE_OP_DELETE))) { 758fab0106SMiklos Szeredi spin_lock(&dentry->d_lock); 768fab0106SMiklos Szeredi if (!delete) 778fab0106SMiklos Szeredi dentry->d_flags &= ~DCACHE_OP_DELETE; 788fab0106SMiklos Szeredi else 798fab0106SMiklos Szeredi dentry->d_flags |= DCACHE_OP_DELETE; 808fab0106SMiklos Szeredi spin_unlock(&dentry->d_lock); 810a0898cfSMiklos Szeredi } 820a0898cfSMiklos Szeredi 8330c6a23dSKhazhismel Kumykov __fuse_dentry_settime(dentry, time); 840a0898cfSMiklos Szeredi } 850a0898cfSMiklos Szeredi 866f9f1180SMiklos Szeredi /* 876f9f1180SMiklos Szeredi * FUSE caches dentries and attributes with separate timeout. The 886f9f1180SMiklos Szeredi * time in jiffies until the dentry/attributes are valid is stored in 89f75fdf22SMiklos Szeredi * dentry->d_fsdata and fuse_inode->i_time respectively. 906f9f1180SMiklos Szeredi */ 916f9f1180SMiklos Szeredi 926f9f1180SMiklos Szeredi /* 936f9f1180SMiklos Szeredi * Calculate the time in jiffies until a dentry/attributes are valid 946f9f1180SMiklos Szeredi */ 959dc10a54SMiklos Szeredi u64 fuse_time_to_jiffies(u64 sec, u32 nsec) 96e5e5558eSMiklos Szeredi { 97685d16ddSMiklos Szeredi if (sec || nsec) { 98bcb6f6d2SMiklos Szeredi struct timespec64 ts = { 99bcb6f6d2SMiklos Szeredi sec, 10021067527SDavid Sheets min_t(u32, nsec, NSEC_PER_SEC - 1) 101bcb6f6d2SMiklos Szeredi }; 102bcb6f6d2SMiklos Szeredi 103bcb6f6d2SMiklos Szeredi return get_jiffies_64() + timespec64_to_jiffies(&ts); 104685d16ddSMiklos Szeredi } else 1050a0898cfSMiklos Szeredi return 0; 106e5e5558eSMiklos Szeredi } 107e5e5558eSMiklos Szeredi 1086f9f1180SMiklos Szeredi /* 1096f9f1180SMiklos Szeredi * Set dentry and possibly attribute timeouts from the lookup/mk* 1106f9f1180SMiklos Szeredi * replies 1116f9f1180SMiklos Szeredi */ 112d123d8e1SMiklos Szeredi void fuse_change_entry_timeout(struct dentry *entry, struct fuse_entry_out *o) 1130aa7c699SMiklos Szeredi { 1140a0898cfSMiklos Szeredi fuse_dentry_settime(entry, 1159dc10a54SMiklos Szeredi fuse_time_to_jiffies(o->entry_valid, o->entry_valid_nsec)); 1168cbdf1e6SMiklos Szeredi } 1178cbdf1e6SMiklos Szeredi 118fa5eee57SMiklos Szeredi void fuse_invalidate_attr_mask(struct inode *inode, u32 mask) 1192f1e8196SMiklos Szeredi { 1202f1e8196SMiklos Szeredi set_mask_bits(&get_fuse_inode(inode)->inval_mask, 0, mask); 1212f1e8196SMiklos Szeredi } 1222f1e8196SMiklos Szeredi 1236f9f1180SMiklos Szeredi /* 1246f9f1180SMiklos Szeredi * Mark the attributes as stale, so that at the next call to 1256f9f1180SMiklos Szeredi * ->getattr() they will be fetched from userspace 1266f9f1180SMiklos Szeredi */ 1278cbdf1e6SMiklos Szeredi void fuse_invalidate_attr(struct inode *inode) 1288cbdf1e6SMiklos Szeredi { 1292f1e8196SMiklos Szeredi fuse_invalidate_attr_mask(inode, STATX_BASIC_STATS); 1308cbdf1e6SMiklos Szeredi } 1318cbdf1e6SMiklos Szeredi 132261aaba7SMiklos Szeredi static void fuse_dir_changed(struct inode *dir) 133261aaba7SMiklos Szeredi { 134261aaba7SMiklos Szeredi fuse_invalidate_attr(dir); 135261aaba7SMiklos Szeredi inode_maybe_inc_iversion(dir, false); 136261aaba7SMiklos Szeredi } 137261aaba7SMiklos Szeredi 13806bbb761SRandy Dunlap /* 139451418fcSAndrew Gallagher * Mark the attributes as stale due to an atime change. Avoid the invalidate if 140451418fcSAndrew Gallagher * atime is not used. 141451418fcSAndrew Gallagher */ 142451418fcSAndrew Gallagher void fuse_invalidate_atime(struct inode *inode) 143451418fcSAndrew Gallagher { 144451418fcSAndrew Gallagher if (!IS_RDONLY(inode)) 1452f1e8196SMiklos Szeredi fuse_invalidate_attr_mask(inode, STATX_ATIME); 146451418fcSAndrew Gallagher } 147451418fcSAndrew Gallagher 1486f9f1180SMiklos Szeredi /* 1496f9f1180SMiklos Szeredi * Just mark the entry as stale, so that a next attempt to look it up 1506f9f1180SMiklos Szeredi * will result in a new lookup call to userspace 1516f9f1180SMiklos Szeredi * 1526f9f1180SMiklos Szeredi * This is called when a dentry is about to become negative and the 1536f9f1180SMiklos Szeredi * timeout is unknown (unlink, rmdir, rename and in some cases 1546f9f1180SMiklos Szeredi * lookup) 1556f9f1180SMiklos Szeredi */ 156dbd561d2SMiklos Szeredi void fuse_invalidate_entry_cache(struct dentry *entry) 1578cbdf1e6SMiklos Szeredi { 1580a0898cfSMiklos Szeredi fuse_dentry_settime(entry, 0); 1598cbdf1e6SMiklos Szeredi } 1608cbdf1e6SMiklos Szeredi 1616f9f1180SMiklos Szeredi /* 1626f9f1180SMiklos Szeredi * Same as fuse_invalidate_entry_cache(), but also try to remove the 1636f9f1180SMiklos Szeredi * dentry from the hash 1646f9f1180SMiklos Szeredi */ 1658cbdf1e6SMiklos Szeredi static void fuse_invalidate_entry(struct dentry *entry) 1668cbdf1e6SMiklos Szeredi { 1678cbdf1e6SMiklos Szeredi d_invalidate(entry); 1688cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 1690aa7c699SMiklos Szeredi } 1700aa7c699SMiklos Szeredi 1717078187aSMiklos Szeredi static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_args *args, 17213983d06SAl Viro u64 nodeid, const struct qstr *name, 173e5e5558eSMiklos Szeredi struct fuse_entry_out *outarg) 174e5e5558eSMiklos Szeredi { 1750e9663eeSMiklos Szeredi memset(outarg, 0, sizeof(struct fuse_entry_out)); 176d5b48543SMiklos Szeredi args->opcode = FUSE_LOOKUP; 177d5b48543SMiklos Szeredi args->nodeid = nodeid; 178d5b48543SMiklos Szeredi args->in_numargs = 1; 179d5b48543SMiklos Szeredi args->in_args[0].size = name->len + 1; 180d5b48543SMiklos Szeredi args->in_args[0].value = name->name; 181d5b48543SMiklos Szeredi args->out_numargs = 1; 182d5b48543SMiklos Szeredi args->out_args[0].size = sizeof(struct fuse_entry_out); 183d5b48543SMiklos Szeredi args->out_args[0].value = outarg; 184e5e5558eSMiklos Szeredi } 185e5e5558eSMiklos Szeredi 1866f9f1180SMiklos Szeredi /* 1876f9f1180SMiklos Szeredi * Check whether the dentry is still valid 1886f9f1180SMiklos Szeredi * 1896f9f1180SMiklos Szeredi * If the entry validity timeout has expired and the dentry is 1906f9f1180SMiklos Szeredi * positive, try to redo the lookup. If the lookup results in a 1916f9f1180SMiklos Szeredi * different inode, then let the VFS invalidate the dentry and redo 1926f9f1180SMiklos Szeredi * the lookup once more. If the lookup results in the same inode, 1936f9f1180SMiklos Szeredi * then refresh the attributes, timeouts and mark the dentry valid. 1946f9f1180SMiklos Szeredi */ 1950b728e19SAl Viro static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) 196e5e5558eSMiklos Szeredi { 19734286d66SNick Piggin struct inode *inode; 19828420dadSMiklos Szeredi struct dentry *parent; 199fcee216bSMax Reitz struct fuse_mount *fm; 2006314efeeSMiklos Szeredi struct fuse_inode *fi; 201e2a6b952SMiklos Szeredi int ret; 2028cbdf1e6SMiklos Szeredi 2032b0143b5SDavid Howells inode = d_inode_rcu(entry); 2045d069dbeSMiklos Szeredi if (inode && fuse_is_bad(inode)) 205e2a6b952SMiklos Szeredi goto invalid; 206154210ccSAnand Avati else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) || 207ccc031e2SJiachen Zhang (flags & (LOOKUP_EXCL | LOOKUP_REVAL | LOOKUP_RENAME_TARGET))) { 208e5e5558eSMiklos Szeredi struct fuse_entry_out outarg; 2097078187aSMiklos Szeredi FUSE_ARGS(args); 21007e77dcaSMiklos Szeredi struct fuse_forget_link *forget; 2111fb69e78SMiklos Szeredi u64 attr_version; 2128cbdf1e6SMiklos Szeredi 21350322fe7SMiklos Szeredi /* For negative dentries, always do a fresh lookup */ 2148cbdf1e6SMiklos Szeredi if (!inode) 215e2a6b952SMiklos Szeredi goto invalid; 2168cbdf1e6SMiklos Szeredi 217e2a6b952SMiklos Szeredi ret = -ECHILD; 2180b728e19SAl Viro if (flags & LOOKUP_RCU) 219e2a6b952SMiklos Szeredi goto out; 220e7c0a167SMiklos Szeredi 221fcee216bSMax Reitz fm = get_fuse_mount(inode); 222e5e5558eSMiklos Szeredi 22307e77dcaSMiklos Szeredi forget = fuse_alloc_forget(); 224e2a6b952SMiklos Szeredi ret = -ENOMEM; 2257078187aSMiklos Szeredi if (!forget) 226e2a6b952SMiklos Szeredi goto out; 2272d51013eSMiklos Szeredi 228fcee216bSMax Reitz attr_version = fuse_get_attr_version(fm->fc); 2291fb69e78SMiklos Szeredi 230e956edd0SMiklos Szeredi parent = dget_parent(entry); 231fcee216bSMax Reitz fuse_lookup_init(fm->fc, &args, get_node_id(d_inode(parent)), 232c180eebeSMiklos Szeredi &entry->d_name, &outarg); 233fcee216bSMax Reitz ret = fuse_simple_request(fm, &args); 234e956edd0SMiklos Szeredi dput(parent); 23550322fe7SMiklos Szeredi /* Zero nodeid is same as -ENOENT */ 2367078187aSMiklos Szeredi if (!ret && !outarg.nodeid) 2377078187aSMiklos Szeredi ret = -ENOENT; 2387078187aSMiklos Szeredi if (!ret) { 2396314efeeSMiklos Szeredi fi = get_fuse_inode(inode); 240bf109c64SMax Reitz if (outarg.nodeid != get_node_id(inode) || 241bf109c64SMax Reitz (bool) IS_AUTOMOUNT(inode) != (bool) (outarg.attr.flags & FUSE_ATTR_SUBMOUNT)) { 242fcee216bSMax Reitz fuse_queue_forget(fm->fc, forget, 243fcee216bSMax Reitz outarg.nodeid, 1); 244e2a6b952SMiklos Szeredi goto invalid; 2459e6268dbSMiklos Szeredi } 246c9d8f5f0SKirill Tkhai spin_lock(&fi->lock); 2479e6268dbSMiklos Szeredi fi->nlookup++; 248c9d8f5f0SKirill Tkhai spin_unlock(&fi->lock); 2499e6268dbSMiklos Szeredi } 25007e77dcaSMiklos Szeredi kfree(forget); 251a9d1c4c6SMiklos Szeredi if (ret == -ENOMEM || ret == -EINTR) 2527078187aSMiklos Szeredi goto out; 253eb59bd17SMiklos Szeredi if (ret || fuse_invalid_attr(&outarg.attr) || 25415db1683SAmir Goldstein fuse_stale_inode(inode, outarg.generation, &outarg.attr)) 255e2a6b952SMiklos Szeredi goto invalid; 256e5e5558eSMiklos Szeredi 25760bcc88aSSeth Forshee forget_all_cached_acls(inode); 258972f4c46SMiklos Szeredi fuse_change_attributes(inode, &outarg.attr, NULL, 2599dc10a54SMiklos Szeredi ATTR_TIMEOUT(&outarg), 2601fb69e78SMiklos Szeredi attr_version); 2611fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outarg); 26228420dadSMiklos Szeredi } else if (inode) { 2636314efeeSMiklos Szeredi fi = get_fuse_inode(inode); 2646314efeeSMiklos Szeredi if (flags & LOOKUP_RCU) { 2656314efeeSMiklos Szeredi if (test_bit(FUSE_I_INIT_RDPLUS, &fi->state)) 2666314efeeSMiklos Szeredi return -ECHILD; 2676314efeeSMiklos Szeredi } else if (test_and_clear_bit(FUSE_I_INIT_RDPLUS, &fi->state)) { 26828420dadSMiklos Szeredi parent = dget_parent(entry); 2692b0143b5SDavid Howells fuse_advise_use_readdirplus(d_inode(parent)); 27028420dadSMiklos Szeredi dput(parent); 271e5e5558eSMiklos Szeredi } 27228420dadSMiklos Szeredi } 273e2a6b952SMiklos Szeredi ret = 1; 274e2a6b952SMiklos Szeredi out: 275e2a6b952SMiklos Szeredi return ret; 276e2a6b952SMiklos Szeredi 277e2a6b952SMiklos Szeredi invalid: 278e2a6b952SMiklos Szeredi ret = 0; 279e2a6b952SMiklos Szeredi goto out; 280e5e5558eSMiklos Szeredi } 281e5e5558eSMiklos Szeredi 28230c6a23dSKhazhismel Kumykov #if BITS_PER_LONG < 64 283f75fdf22SMiklos Szeredi static int fuse_dentry_init(struct dentry *dentry) 284f75fdf22SMiklos Szeredi { 285dc69e98cSKhazhismel Kumykov dentry->d_fsdata = kzalloc(sizeof(union fuse_dentry), 286dc69e98cSKhazhismel Kumykov GFP_KERNEL_ACCOUNT | __GFP_RECLAIMABLE); 287f75fdf22SMiklos Szeredi 288f75fdf22SMiklos Szeredi return dentry->d_fsdata ? 0 : -ENOMEM; 289f75fdf22SMiklos Szeredi } 290f75fdf22SMiklos Szeredi static void fuse_dentry_release(struct dentry *dentry) 291f75fdf22SMiklos Szeredi { 292f75fdf22SMiklos Szeredi union fuse_dentry *fd = dentry->d_fsdata; 293f75fdf22SMiklos Szeredi 294f75fdf22SMiklos Szeredi kfree_rcu(fd, rcu); 295f75fdf22SMiklos Szeredi } 29630c6a23dSKhazhismel Kumykov #endif 297f75fdf22SMiklos Szeredi 2988fab0106SMiklos Szeredi static int fuse_dentry_delete(const struct dentry *dentry) 2998fab0106SMiklos Szeredi { 3008fab0106SMiklos Szeredi return time_before64(fuse_dentry_time(dentry), get_jiffies_64()); 3018fab0106SMiklos Szeredi } 3028fab0106SMiklos Szeredi 303bf109c64SMax Reitz /* 304bf109c64SMax Reitz * Create a fuse_mount object with a new superblock (with path->dentry 305bf109c64SMax Reitz * as the root), and return that mount so it can be auto-mounted on 306bf109c64SMax Reitz * @path. 307bf109c64SMax Reitz */ 308bf109c64SMax Reitz static struct vfsmount *fuse_dentry_automount(struct path *path) 309bf109c64SMax Reitz { 310bf109c64SMax Reitz struct fs_context *fsc; 311bf109c64SMax Reitz struct vfsmount *mnt; 312bf109c64SMax Reitz struct fuse_inode *mp_fi = get_fuse_inode(d_inode(path->dentry)); 313bf109c64SMax Reitz 314bf109c64SMax Reitz fsc = fs_context_for_submount(path->mnt->mnt_sb->s_type, path->dentry); 31529e0e4dfSGreg Kurz if (IS_ERR(fsc)) 31629e0e4dfSGreg Kurz return ERR_CAST(fsc); 317bf109c64SMax Reitz 318266eb3f2SGreg Kurz /* Pass the FUSE inode of the mount for fuse_get_tree_submount() */ 319266eb3f2SGreg Kurz fsc->fs_private = mp_fi; 320266eb3f2SGreg Kurz 321bf109c64SMax Reitz /* Create the submount */ 32229e0e4dfSGreg Kurz mnt = fc_mount(fsc); 32329e0e4dfSGreg Kurz if (!IS_ERR(mnt)) 324bf109c64SMax Reitz mntget(mnt); 32529e0e4dfSGreg Kurz 326bf109c64SMax Reitz put_fs_context(fsc); 327bf109c64SMax Reitz return mnt; 328bf109c64SMax Reitz } 329bf109c64SMax Reitz 3304269590aSAl Viro const struct dentry_operations fuse_dentry_operations = { 331e5e5558eSMiklos Szeredi .d_revalidate = fuse_dentry_revalidate, 3328fab0106SMiklos Szeredi .d_delete = fuse_dentry_delete, 33330c6a23dSKhazhismel Kumykov #if BITS_PER_LONG < 64 334f75fdf22SMiklos Szeredi .d_init = fuse_dentry_init, 335f75fdf22SMiklos Szeredi .d_release = fuse_dentry_release, 33630c6a23dSKhazhismel Kumykov #endif 337bf109c64SMax Reitz .d_automount = fuse_dentry_automount, 338e5e5558eSMiklos Szeredi }; 339e5e5558eSMiklos Szeredi 3400ce267ffSMiklos Szeredi const struct dentry_operations fuse_root_dentry_operations = { 34130c6a23dSKhazhismel Kumykov #if BITS_PER_LONG < 64 3420ce267ffSMiklos Szeredi .d_init = fuse_dentry_init, 3430ce267ffSMiklos Szeredi .d_release = fuse_dentry_release, 34430c6a23dSKhazhismel Kumykov #endif 3450ce267ffSMiklos Szeredi }; 3460ce267ffSMiklos Szeredi 347a5bfffacSTimo Savola int fuse_valid_type(int m) 34839ee059aSMiklos Szeredi { 34939ee059aSMiklos Szeredi return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) || 35039ee059aSMiklos Szeredi S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); 35139ee059aSMiklos Szeredi } 35239ee059aSMiklos Szeredi 353d3045530SMiklos Szeredi static bool fuse_valid_size(u64 size) 354d3045530SMiklos Szeredi { 355d3045530SMiklos Szeredi return size <= LLONG_MAX; 356d3045530SMiklos Szeredi } 357d3045530SMiklos Szeredi 358eb59bd17SMiklos Szeredi bool fuse_invalid_attr(struct fuse_attr *attr) 359eb59bd17SMiklos Szeredi { 360d3045530SMiklos Szeredi return !fuse_valid_type(attr->mode) || !fuse_valid_size(attr->size); 361eb59bd17SMiklos Szeredi } 362eb59bd17SMiklos Szeredi 36313983d06SAl Viro int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name, 364c180eebeSMiklos Szeredi struct fuse_entry_out *outarg, struct inode **inode) 365c180eebeSMiklos Szeredi { 366fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount_super(sb); 3677078187aSMiklos Szeredi FUSE_ARGS(args); 36807e77dcaSMiklos Szeredi struct fuse_forget_link *forget; 369c180eebeSMiklos Szeredi u64 attr_version; 370c180eebeSMiklos Szeredi int err; 371c180eebeSMiklos Szeredi 372c180eebeSMiklos Szeredi *inode = NULL; 373c180eebeSMiklos Szeredi err = -ENAMETOOLONG; 374c180eebeSMiklos Szeredi if (name->len > FUSE_NAME_MAX) 375c180eebeSMiklos Szeredi goto out; 376c180eebeSMiklos Szeredi 377c180eebeSMiklos Szeredi 37807e77dcaSMiklos Szeredi forget = fuse_alloc_forget(); 37907e77dcaSMiklos Szeredi err = -ENOMEM; 3807078187aSMiklos Szeredi if (!forget) 381c180eebeSMiklos Szeredi goto out; 382c180eebeSMiklos Szeredi 383fcee216bSMax Reitz attr_version = fuse_get_attr_version(fm->fc); 384c180eebeSMiklos Szeredi 385fcee216bSMax Reitz fuse_lookup_init(fm->fc, &args, nodeid, name, outarg); 386fcee216bSMax Reitz err = fuse_simple_request(fm, &args); 387c180eebeSMiklos Szeredi /* Zero nodeid is same as -ENOENT, but with valid timeout */ 388c180eebeSMiklos Szeredi if (err || !outarg->nodeid) 389c180eebeSMiklos Szeredi goto out_put_forget; 390c180eebeSMiklos Szeredi 391c180eebeSMiklos Szeredi err = -EIO; 392eb59bd17SMiklos Szeredi if (fuse_invalid_attr(&outarg->attr)) 393c180eebeSMiklos Szeredi goto out_put_forget; 394c180eebeSMiklos Szeredi 395c180eebeSMiklos Szeredi *inode = fuse_iget(sb, outarg->nodeid, outarg->generation, 3969dc10a54SMiklos Szeredi &outarg->attr, ATTR_TIMEOUT(outarg), 397c180eebeSMiklos Szeredi attr_version); 398c180eebeSMiklos Szeredi err = -ENOMEM; 399c180eebeSMiklos Szeredi if (!*inode) { 400fcee216bSMax Reitz fuse_queue_forget(fm->fc, forget, outarg->nodeid, 1); 401c180eebeSMiklos Szeredi goto out; 402c180eebeSMiklos Szeredi } 403c180eebeSMiklos Szeredi err = 0; 404c180eebeSMiklos Szeredi 405c180eebeSMiklos Szeredi out_put_forget: 40607e77dcaSMiklos Szeredi kfree(forget); 407c180eebeSMiklos Szeredi out: 408c180eebeSMiklos Szeredi return err; 409c180eebeSMiklos Szeredi } 410c180eebeSMiklos Szeredi 4110aa7c699SMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, 41200cd8dd3SAl Viro unsigned int flags) 413e5e5558eSMiklos Szeredi { 414e5e5558eSMiklos Szeredi int err; 415e5e5558eSMiklos Szeredi struct fuse_entry_out outarg; 416c180eebeSMiklos Szeredi struct inode *inode; 4170de6256dSMiklos Szeredi struct dentry *newent; 418c180eebeSMiklos Szeredi bool outarg_valid = true; 41963576c13SMiklos Szeredi bool locked; 420e5e5558eSMiklos Szeredi 4215d069dbeSMiklos Szeredi if (fuse_is_bad(dir)) 4225d069dbeSMiklos Szeredi return ERR_PTR(-EIO); 4235d069dbeSMiklos Szeredi 42463576c13SMiklos Szeredi locked = fuse_lock_inode(dir); 425c180eebeSMiklos Szeredi err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name, 426c180eebeSMiklos Szeredi &outarg, &inode); 42763576c13SMiklos Szeredi fuse_unlock_inode(dir, locked); 428c180eebeSMiklos Szeredi if (err == -ENOENT) { 429c180eebeSMiklos Szeredi outarg_valid = false; 430c180eebeSMiklos Szeredi err = 0; 4312d51013eSMiklos Szeredi } 432c180eebeSMiklos Szeredi if (err) 433c180eebeSMiklos Szeredi goto out_err; 4342d51013eSMiklos Szeredi 435ee4e5271SMiklos Szeredi err = -EIO; 436c180eebeSMiklos Szeredi if (inode && get_node_id(inode) == FUSE_ROOT_ID) 437c180eebeSMiklos Szeredi goto out_iput; 438e5e5558eSMiklos Szeredi 43941d28bcaSAl Viro newent = d_splice_alias(inode, entry); 440c180eebeSMiklos Szeredi err = PTR_ERR(newent); 441c180eebeSMiklos Szeredi if (IS_ERR(newent)) 4425835f339SMiklos Szeredi goto out_err; 443d2a85164SMiklos Szeredi 4440de6256dSMiklos Szeredi entry = newent ? newent : entry; 445c180eebeSMiklos Szeredi if (outarg_valid) 4461fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outarg); 4478cbdf1e6SMiklos Szeredi else 4488cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 449c180eebeSMiklos Szeredi 4506c26f717SMiklos Szeredi if (inode) 4514582a4abSFeng Shuo fuse_advise_use_readdirplus(dir); 4520de6256dSMiklos Szeredi return newent; 453c180eebeSMiklos Szeredi 454c180eebeSMiklos Szeredi out_iput: 455c180eebeSMiklos Szeredi iput(inode); 456c180eebeSMiklos Szeredi out_err: 457c180eebeSMiklos Szeredi return ERR_PTR(err); 458e5e5558eSMiklos Szeredi } 459e5e5558eSMiklos Szeredi 4603e2b6fdbSVivek Goyal static int get_security_context(struct dentry *entry, umode_t mode, 46115d937d7SMiklos Szeredi struct fuse_in_arg *ext) 4623e2b6fdbSVivek Goyal { 4633e2b6fdbSVivek Goyal struct fuse_secctx *fctx; 4643e2b6fdbSVivek Goyal struct fuse_secctx_header *header; 4653e2b6fdbSVivek Goyal void *ctx = NULL, *ptr; 4663e2b6fdbSVivek Goyal u32 ctxlen, total_len = sizeof(*header); 4673e2b6fdbSVivek Goyal int err, nr_ctx = 0; 4683e2b6fdbSVivek Goyal const char *name; 4693e2b6fdbSVivek Goyal size_t namelen; 4703e2b6fdbSVivek Goyal 4713e2b6fdbSVivek Goyal err = security_dentry_init_security(entry, mode, &entry->d_name, 4723e2b6fdbSVivek Goyal &name, &ctx, &ctxlen); 4733e2b6fdbSVivek Goyal if (err) { 4743e2b6fdbSVivek Goyal if (err != -EOPNOTSUPP) 4753e2b6fdbSVivek Goyal goto out_err; 4763e2b6fdbSVivek Goyal /* No LSM is supporting this security hook. Ignore error */ 4773e2b6fdbSVivek Goyal ctxlen = 0; 4783e2b6fdbSVivek Goyal ctx = NULL; 4793e2b6fdbSVivek Goyal } 4803e2b6fdbSVivek Goyal 4813e2b6fdbSVivek Goyal if (ctxlen) { 4823e2b6fdbSVivek Goyal nr_ctx = 1; 4833e2b6fdbSVivek Goyal namelen = strlen(name) + 1; 4843e2b6fdbSVivek Goyal err = -EIO; 4853e2b6fdbSVivek Goyal if (WARN_ON(namelen > XATTR_NAME_MAX + 1 || ctxlen > S32_MAX)) 4863e2b6fdbSVivek Goyal goto out_err; 4873e2b6fdbSVivek Goyal total_len += FUSE_REC_ALIGN(sizeof(*fctx) + namelen + ctxlen); 4883e2b6fdbSVivek Goyal } 4893e2b6fdbSVivek Goyal 4903e2b6fdbSVivek Goyal err = -ENOMEM; 4913e2b6fdbSVivek Goyal header = ptr = kzalloc(total_len, GFP_KERNEL); 4923e2b6fdbSVivek Goyal if (!ptr) 4933e2b6fdbSVivek Goyal goto out_err; 4943e2b6fdbSVivek Goyal 4953e2b6fdbSVivek Goyal header->nr_secctx = nr_ctx; 4963e2b6fdbSVivek Goyal header->size = total_len; 4973e2b6fdbSVivek Goyal ptr += sizeof(*header); 4983e2b6fdbSVivek Goyal if (nr_ctx) { 4993e2b6fdbSVivek Goyal fctx = ptr; 5003e2b6fdbSVivek Goyal fctx->size = ctxlen; 5013e2b6fdbSVivek Goyal ptr += sizeof(*fctx); 5023e2b6fdbSVivek Goyal 5033e2b6fdbSVivek Goyal strcpy(ptr, name); 5043e2b6fdbSVivek Goyal ptr += namelen; 5053e2b6fdbSVivek Goyal 5063e2b6fdbSVivek Goyal memcpy(ptr, ctx, ctxlen); 5073e2b6fdbSVivek Goyal } 50815d937d7SMiklos Szeredi ext->size = total_len; 50915d937d7SMiklos Szeredi ext->value = header; 5103e2b6fdbSVivek Goyal err = 0; 5113e2b6fdbSVivek Goyal out_err: 5123e2b6fdbSVivek Goyal kfree(ctx); 5133e2b6fdbSVivek Goyal return err; 5143e2b6fdbSVivek Goyal } 5153e2b6fdbSVivek Goyal 5168ed7cb3fSMiklos Szeredi static void *extend_arg(struct fuse_in_arg *buf, u32 bytes) 5178ed7cb3fSMiklos Szeredi { 5188ed7cb3fSMiklos Szeredi void *p; 5198ed7cb3fSMiklos Szeredi u32 newlen = buf->size + bytes; 5208ed7cb3fSMiklos Szeredi 5218ed7cb3fSMiklos Szeredi p = krealloc(buf->value, newlen, GFP_KERNEL); 5228ed7cb3fSMiklos Szeredi if (!p) { 5238ed7cb3fSMiklos Szeredi kfree(buf->value); 5248ed7cb3fSMiklos Szeredi buf->size = 0; 5258ed7cb3fSMiklos Szeredi buf->value = NULL; 5268ed7cb3fSMiklos Szeredi return NULL; 5278ed7cb3fSMiklos Szeredi } 5288ed7cb3fSMiklos Szeredi 5298ed7cb3fSMiklos Szeredi memset(p + buf->size, 0, bytes); 5308ed7cb3fSMiklos Szeredi buf->value = p; 5318ed7cb3fSMiklos Szeredi buf->size = newlen; 5328ed7cb3fSMiklos Szeredi 5338ed7cb3fSMiklos Szeredi return p + newlen - bytes; 5348ed7cb3fSMiklos Szeredi } 5358ed7cb3fSMiklos Szeredi 5368ed7cb3fSMiklos Szeredi static u32 fuse_ext_size(size_t size) 5378ed7cb3fSMiklos Szeredi { 5388ed7cb3fSMiklos Szeredi return FUSE_REC_ALIGN(sizeof(struct fuse_ext_header) + size); 5398ed7cb3fSMiklos Szeredi } 5408ed7cb3fSMiklos Szeredi 5418ed7cb3fSMiklos Szeredi /* 5428ed7cb3fSMiklos Szeredi * This adds just a single supplementary group that matches the parent's group. 5438ed7cb3fSMiklos Szeredi */ 5448ed7cb3fSMiklos Szeredi static int get_create_supp_group(struct inode *dir, struct fuse_in_arg *ext) 5458ed7cb3fSMiklos Szeredi { 5468ed7cb3fSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 5478ed7cb3fSMiklos Szeredi struct fuse_ext_header *xh; 5488ed7cb3fSMiklos Szeredi struct fuse_supp_groups *sg; 5498ed7cb3fSMiklos Szeredi kgid_t kgid = dir->i_gid; 5508ed7cb3fSMiklos Szeredi gid_t parent_gid = from_kgid(fc->user_ns, kgid); 5518ed7cb3fSMiklos Szeredi u32 sg_len = fuse_ext_size(sizeof(*sg) + sizeof(sg->groups[0])); 5528ed7cb3fSMiklos Szeredi 5538ed7cb3fSMiklos Szeredi if (parent_gid == (gid_t) -1 || gid_eq(kgid, current_fsgid()) || 5548ed7cb3fSMiklos Szeredi !in_group_p(kgid)) 5558ed7cb3fSMiklos Szeredi return 0; 5568ed7cb3fSMiklos Szeredi 5578ed7cb3fSMiklos Szeredi xh = extend_arg(ext, sg_len); 5588ed7cb3fSMiklos Szeredi if (!xh) 5598ed7cb3fSMiklos Szeredi return -ENOMEM; 5608ed7cb3fSMiklos Szeredi 5618ed7cb3fSMiklos Szeredi xh->size = sg_len; 5628ed7cb3fSMiklos Szeredi xh->type = FUSE_EXT_GROUPS; 5638ed7cb3fSMiklos Szeredi 5648ed7cb3fSMiklos Szeredi sg = (struct fuse_supp_groups *) &xh[1]; 5658ed7cb3fSMiklos Szeredi sg->nr_groups = 1; 5668ed7cb3fSMiklos Szeredi sg->groups[0] = parent_gid; 5678ed7cb3fSMiklos Szeredi 5688ed7cb3fSMiklos Szeredi return 0; 5698ed7cb3fSMiklos Szeredi } 5708ed7cb3fSMiklos Szeredi 5718ed7cb3fSMiklos Szeredi static int get_create_ext(struct fuse_args *args, 5728ed7cb3fSMiklos Szeredi struct inode *dir, struct dentry *dentry, 57315d937d7SMiklos Szeredi umode_t mode) 57415d937d7SMiklos Szeredi { 57515d937d7SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(dentry->d_sb); 57615d937d7SMiklos Szeredi struct fuse_in_arg ext = { .size = 0, .value = NULL }; 57715d937d7SMiklos Szeredi int err = 0; 57815d937d7SMiklos Szeredi 57915d937d7SMiklos Szeredi if (fc->init_security) 58015d937d7SMiklos Szeredi err = get_security_context(dentry, mode, &ext); 5818ed7cb3fSMiklos Szeredi if (!err && fc->create_supp_group) 5828ed7cb3fSMiklos Szeredi err = get_create_supp_group(dir, &ext); 58315d937d7SMiklos Szeredi 58415d937d7SMiklos Szeredi if (!err && ext.size) { 58515d937d7SMiklos Szeredi WARN_ON(args->in_numargs >= ARRAY_SIZE(args->in_args)); 58615d937d7SMiklos Szeredi args->is_ext = true; 58715d937d7SMiklos Szeredi args->ext_idx = args->in_numargs++; 58815d937d7SMiklos Szeredi args->in_args[args->ext_idx] = ext; 58915d937d7SMiklos Szeredi } else { 59015d937d7SMiklos Szeredi kfree(ext.value); 59115d937d7SMiklos Szeredi } 59215d937d7SMiklos Szeredi 59315d937d7SMiklos Szeredi return err; 59415d937d7SMiklos Szeredi } 59515d937d7SMiklos Szeredi 59615d937d7SMiklos Szeredi static void free_ext_value(struct fuse_args *args) 59715d937d7SMiklos Szeredi { 59815d937d7SMiklos Szeredi if (args->is_ext) 59915d937d7SMiklos Szeredi kfree(args->in_args[args->ext_idx].value); 60015d937d7SMiklos Szeredi } 60115d937d7SMiklos Szeredi 6026f9f1180SMiklos Szeredi /* 6036f9f1180SMiklos Szeredi * Atomic create+open operation 6046f9f1180SMiklos Szeredi * 6056f9f1180SMiklos Szeredi * If the filesystem doesn't support this, then fall back to separate 6066f9f1180SMiklos Szeredi * 'mknod' + 'open' requests. 6076f9f1180SMiklos Szeredi */ 608d9585277SAl Viro static int fuse_create_open(struct inode *dir, struct dentry *entry, 60954d601cbSMiklos Szeredi struct file *file, unsigned int flags, 6107d375390SMiklos Szeredi umode_t mode, u32 opcode) 611fd72faacSMiklos Szeredi { 612fd72faacSMiklos Szeredi int err; 613fd72faacSMiklos Szeredi struct inode *inode; 614fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(dir); 6157078187aSMiklos Szeredi FUSE_ARGS(args); 61607e77dcaSMiklos Szeredi struct fuse_forget_link *forget; 617e0a43ddcSMiklos Szeredi struct fuse_create_in inarg; 618fd72faacSMiklos Szeredi struct fuse_open_out outopen; 619fd72faacSMiklos Szeredi struct fuse_entry_out outentry; 620ebf84d0cSKirill Tkhai struct fuse_inode *fi; 621fd72faacSMiklos Szeredi struct fuse_file *ff; 6222fdbb8ddSMiklos Szeredi bool trunc = flags & O_TRUNC; 623fd72faacSMiklos Szeredi 624af109bcaSMiklos Szeredi /* Userspace expects S_IFREG in create mode */ 625af109bcaSMiklos Szeredi BUG_ON((mode & S_IFMT) != S_IFREG); 626af109bcaSMiklos Szeredi 62707e77dcaSMiklos Szeredi forget = fuse_alloc_forget(); 628c8ccbe03SMiklos Szeredi err = -ENOMEM; 62907e77dcaSMiklos Szeredi if (!forget) 630c8ccbe03SMiklos Szeredi goto out_err; 63151eb01e7SMiklos Szeredi 632ce1d5a49SMiklos Szeredi err = -ENOMEM; 633fcee216bSMax Reitz ff = fuse_file_alloc(fm); 634fd72faacSMiklos Szeredi if (!ff) 6357078187aSMiklos Szeredi goto out_put_forget_req; 636fd72faacSMiklos Szeredi 637fcee216bSMax Reitz if (!fm->fc->dont_mask) 638e0a43ddcSMiklos Szeredi mode &= ~current_umask(); 639e0a43ddcSMiklos Szeredi 640fd72faacSMiklos Szeredi flags &= ~O_NOCTTY; 641fd72faacSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 6420e9663eeSMiklos Szeredi memset(&outentry, 0, sizeof(outentry)); 643fd72faacSMiklos Szeredi inarg.flags = flags; 644fd72faacSMiklos Szeredi inarg.mode = mode; 645e0a43ddcSMiklos Szeredi inarg.umask = current_umask(); 646643a666aSVivek Goyal 6472fdbb8ddSMiklos Szeredi if (fm->fc->handle_killpriv_v2 && trunc && 648643a666aSVivek Goyal !(flags & O_EXCL) && !capable(CAP_FSETID)) { 649643a666aSVivek Goyal inarg.open_flags |= FUSE_OPEN_KILL_SUIDGID; 650643a666aSVivek Goyal } 651643a666aSVivek Goyal 6527d375390SMiklos Szeredi args.opcode = opcode; 653d5b48543SMiklos Szeredi args.nodeid = get_node_id(dir); 654d5b48543SMiklos Szeredi args.in_numargs = 2; 655d5b48543SMiklos Szeredi args.in_args[0].size = sizeof(inarg); 656d5b48543SMiklos Szeredi args.in_args[0].value = &inarg; 657d5b48543SMiklos Szeredi args.in_args[1].size = entry->d_name.len + 1; 658d5b48543SMiklos Szeredi args.in_args[1].value = entry->d_name.name; 659d5b48543SMiklos Szeredi args.out_numargs = 2; 660d5b48543SMiklos Szeredi args.out_args[0].size = sizeof(outentry); 661d5b48543SMiklos Szeredi args.out_args[0].value = &outentry; 662d5b48543SMiklos Szeredi args.out_args[1].size = sizeof(outopen); 663d5b48543SMiklos Szeredi args.out_args[1].value = &outopen; 6643e2b6fdbSVivek Goyal 6658ed7cb3fSMiklos Szeredi err = get_create_ext(&args, dir, entry, mode); 6663e2b6fdbSVivek Goyal if (err) 6673e2b6fdbSVivek Goyal goto out_put_forget_req; 6683e2b6fdbSVivek Goyal 669fcee216bSMax Reitz err = fuse_simple_request(fm, &args); 67015d937d7SMiklos Szeredi free_ext_value(&args); 671c8ccbe03SMiklos Szeredi if (err) 672fd72faacSMiklos Szeredi goto out_free_ff; 673fd72faacSMiklos Szeredi 674fd72faacSMiklos Szeredi err = -EIO; 675eb59bd17SMiklos Szeredi if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid) || 676eb59bd17SMiklos Szeredi fuse_invalid_attr(&outentry.attr)) 677fd72faacSMiklos Szeredi goto out_free_ff; 678fd72faacSMiklos Szeredi 679c7b7143cSMiklos Szeredi ff->fh = outopen.fh; 680c7b7143cSMiklos Szeredi ff->nodeid = outentry.nodeid; 681c7b7143cSMiklos Szeredi ff->open_flags = outopen.open_flags; 682fd72faacSMiklos Szeredi inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, 6839dc10a54SMiklos Szeredi &outentry.attr, ATTR_TIMEOUT(&outentry), 0); 684fd72faacSMiklos Szeredi if (!inode) { 685fd72faacSMiklos Szeredi flags &= ~(O_CREAT | O_EXCL | O_TRUNC); 686ebf84d0cSKirill Tkhai fuse_sync_release(NULL, ff, flags); 687fcee216bSMax Reitz fuse_queue_forget(fm->fc, forget, outentry.nodeid, 1); 688c8ccbe03SMiklos Szeredi err = -ENOMEM; 689c8ccbe03SMiklos Szeredi goto out_err; 690fd72faacSMiklos Szeredi } 69107e77dcaSMiklos Szeredi kfree(forget); 692fd72faacSMiklos Szeredi d_instantiate(entry, inode); 6931fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outentry); 694261aaba7SMiklos Szeredi fuse_dir_changed(dir); 695be12af3eSAl Viro err = finish_open(file, entry, generic_file_open); 69630d90494SAl Viro if (err) { 697ebf84d0cSKirill Tkhai fi = get_fuse_inode(inode); 698ebf84d0cSKirill Tkhai fuse_sync_release(fi, ff, flags); 699c8ccbe03SMiklos Szeredi } else { 700267d8444SMiklos Szeredi file->private_data = ff; 701c7b7143cSMiklos Szeredi fuse_finish_open(inode, file); 7022fdbb8ddSMiklos Szeredi if (fm->fc->atomic_o_trunc && trunc) 7032fdbb8ddSMiklos Szeredi truncate_pagecache(inode, 0); 7042fdbb8ddSMiklos Szeredi else if (!(ff->open_flags & FOPEN_KEEP_CACHE)) 7052fdbb8ddSMiklos Szeredi invalidate_inode_pages2(inode->i_mapping); 706c8ccbe03SMiklos Szeredi } 707d9585277SAl Viro return err; 708fd72faacSMiklos Szeredi 709fd72faacSMiklos Szeredi out_free_ff: 710fd72faacSMiklos Szeredi fuse_file_free(ff); 71151eb01e7SMiklos Szeredi out_put_forget_req: 71207e77dcaSMiklos Szeredi kfree(forget); 713c8ccbe03SMiklos Szeredi out_err: 714d9585277SAl Viro return err; 715c8ccbe03SMiklos Szeredi } 716c8ccbe03SMiklos Szeredi 7175ebb29beSChristian Brauner static int fuse_mknod(struct mnt_idmap *, struct inode *, struct dentry *, 718549c7297SChristian Brauner umode_t, dev_t); 719d9585277SAl Viro static int fuse_atomic_open(struct inode *dir, struct dentry *entry, 72030d90494SAl Viro struct file *file, unsigned flags, 72144907d79SAl Viro umode_t mode) 722c8ccbe03SMiklos Szeredi { 723c8ccbe03SMiklos Szeredi int err; 724c8ccbe03SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 725c8ccbe03SMiklos Szeredi struct dentry *res = NULL; 726c8ccbe03SMiklos Szeredi 7275d069dbeSMiklos Szeredi if (fuse_is_bad(dir)) 7285d069dbeSMiklos Szeredi return -EIO; 7295d069dbeSMiklos Szeredi 73000699ad8SAl Viro if (d_in_lookup(entry)) { 73100cd8dd3SAl Viro res = fuse_lookup(dir, entry, 0); 732c8ccbe03SMiklos Szeredi if (IS_ERR(res)) 733d9585277SAl Viro return PTR_ERR(res); 734c8ccbe03SMiklos Szeredi 735c8ccbe03SMiklos Szeredi if (res) 736c8ccbe03SMiklos Szeredi entry = res; 737c8ccbe03SMiklos Szeredi } 738c8ccbe03SMiklos Szeredi 7392b0143b5SDavid Howells if (!(flags & O_CREAT) || d_really_is_positive(entry)) 740c8ccbe03SMiklos Szeredi goto no_open; 741c8ccbe03SMiklos Szeredi 742c8ccbe03SMiklos Szeredi /* Only creates */ 74373a09dd9SAl Viro file->f_mode |= FMODE_CREATED; 744c8ccbe03SMiklos Szeredi 745c8ccbe03SMiklos Szeredi if (fc->no_create) 746c8ccbe03SMiklos Szeredi goto mknod; 747c8ccbe03SMiklos Szeredi 7487d375390SMiklos Szeredi err = fuse_create_open(dir, entry, file, flags, mode, FUSE_CREATE); 749d9585277SAl Viro if (err == -ENOSYS) { 750c8ccbe03SMiklos Szeredi fc->no_create = 1; 751c8ccbe03SMiklos Szeredi goto mknod; 7527d875e66SJiachen Zhang } else if (err == -EEXIST) 7537d875e66SJiachen Zhang fuse_invalidate_entry(entry); 754c8ccbe03SMiklos Szeredi out_dput: 755c8ccbe03SMiklos Szeredi dput(res); 756d9585277SAl Viro return err; 757c8ccbe03SMiklos Szeredi 758c8ccbe03SMiklos Szeredi mknod: 7595ebb29beSChristian Brauner err = fuse_mknod(&nop_mnt_idmap, dir, entry, mode, 0); 760d9585277SAl Viro if (err) 761c8ccbe03SMiklos Szeredi goto out_dput; 762c8ccbe03SMiklos Szeredi no_open: 763e45198a6SAl Viro return finish_no_open(file, res); 764fd72faacSMiklos Szeredi } 765fd72faacSMiklos Szeredi 7666f9f1180SMiklos Szeredi /* 7676f9f1180SMiklos Szeredi * Code shared between mknod, mkdir, symlink and link 7686f9f1180SMiklos Szeredi */ 769fcee216bSMax Reitz static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args, 7709e6268dbSMiklos Szeredi struct inode *dir, struct dentry *entry, 771541af6a0SAl Viro umode_t mode) 7729e6268dbSMiklos Szeredi { 7739e6268dbSMiklos Szeredi struct fuse_entry_out outarg; 7749e6268dbSMiklos Szeredi struct inode *inode; 775c971e6a0SAl Viro struct dentry *d; 7769e6268dbSMiklos Szeredi int err; 77707e77dcaSMiklos Szeredi struct fuse_forget_link *forget; 7782d51013eSMiklos Szeredi 7795d069dbeSMiklos Szeredi if (fuse_is_bad(dir)) 7805d069dbeSMiklos Szeredi return -EIO; 7815d069dbeSMiklos Szeredi 78207e77dcaSMiklos Szeredi forget = fuse_alloc_forget(); 7837078187aSMiklos Szeredi if (!forget) 78407e77dcaSMiklos Szeredi return -ENOMEM; 7859e6268dbSMiklos Szeredi 7860e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 787d5b48543SMiklos Szeredi args->nodeid = get_node_id(dir); 788d5b48543SMiklos Szeredi args->out_numargs = 1; 789d5b48543SMiklos Szeredi args->out_args[0].size = sizeof(outarg); 790d5b48543SMiklos Szeredi args->out_args[0].value = &outarg; 7913e2b6fdbSVivek Goyal 79215d937d7SMiklos Szeredi if (args->opcode != FUSE_LINK) { 7938ed7cb3fSMiklos Szeredi err = get_create_ext(args, dir, entry, mode); 7943e2b6fdbSVivek Goyal if (err) 7953e2b6fdbSVivek Goyal goto out_put_forget_req; 7963e2b6fdbSVivek Goyal } 7973e2b6fdbSVivek Goyal 798fcee216bSMax Reitz err = fuse_simple_request(fm, args); 79915d937d7SMiklos Szeredi free_ext_value(args); 8002d51013eSMiklos Szeredi if (err) 8012d51013eSMiklos Szeredi goto out_put_forget_req; 8022d51013eSMiklos Szeredi 80339ee059aSMiklos Szeredi err = -EIO; 804eb59bd17SMiklos Szeredi if (invalid_nodeid(outarg.nodeid) || fuse_invalid_attr(&outarg.attr)) 8052d51013eSMiklos Szeredi goto out_put_forget_req; 80639ee059aSMiklos Szeredi 80739ee059aSMiklos Szeredi if ((outarg.attr.mode ^ mode) & S_IFMT) 8082d51013eSMiklos Szeredi goto out_put_forget_req; 80939ee059aSMiklos Szeredi 8109e6268dbSMiklos Szeredi inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 8119dc10a54SMiklos Szeredi &outarg.attr, ATTR_TIMEOUT(&outarg), 0); 8129e6268dbSMiklos Szeredi if (!inode) { 813fcee216bSMax Reitz fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1); 8149e6268dbSMiklos Szeredi return -ENOMEM; 8159e6268dbSMiklos Szeredi } 81607e77dcaSMiklos Szeredi kfree(forget); 8179e6268dbSMiklos Szeredi 818c971e6a0SAl Viro d_drop(entry); 819c971e6a0SAl Viro d = d_splice_alias(inode, entry); 820c971e6a0SAl Viro if (IS_ERR(d)) 821c971e6a0SAl Viro return PTR_ERR(d); 822d2a85164SMiklos Szeredi 823c971e6a0SAl Viro if (d) { 824c971e6a0SAl Viro fuse_change_entry_timeout(d, &outarg); 825c971e6a0SAl Viro dput(d); 826c971e6a0SAl Viro } else { 8271fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outarg); 828c971e6a0SAl Viro } 829261aaba7SMiklos Szeredi fuse_dir_changed(dir); 8309e6268dbSMiklos Szeredi return 0; 83139ee059aSMiklos Szeredi 8322d51013eSMiklos Szeredi out_put_forget_req: 8337d875e66SJiachen Zhang if (err == -EEXIST) 8347d875e66SJiachen Zhang fuse_invalidate_entry(entry); 83507e77dcaSMiklos Szeredi kfree(forget); 83639ee059aSMiklos Szeredi return err; 8379e6268dbSMiklos Szeredi } 8389e6268dbSMiklos Szeredi 8395ebb29beSChristian Brauner static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir, 840549c7297SChristian Brauner struct dentry *entry, umode_t mode, dev_t rdev) 8419e6268dbSMiklos Szeredi { 8429e6268dbSMiklos Szeredi struct fuse_mknod_in inarg; 843fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(dir); 8447078187aSMiklos Szeredi FUSE_ARGS(args); 8459e6268dbSMiklos Szeredi 846fcee216bSMax Reitz if (!fm->fc->dont_mask) 847e0a43ddcSMiklos Szeredi mode &= ~current_umask(); 848e0a43ddcSMiklos Szeredi 8499e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 8509e6268dbSMiklos Szeredi inarg.mode = mode; 8519e6268dbSMiklos Szeredi inarg.rdev = new_encode_dev(rdev); 852e0a43ddcSMiklos Szeredi inarg.umask = current_umask(); 853d5b48543SMiklos Szeredi args.opcode = FUSE_MKNOD; 854d5b48543SMiklos Szeredi args.in_numargs = 2; 855d5b48543SMiklos Szeredi args.in_args[0].size = sizeof(inarg); 856d5b48543SMiklos Szeredi args.in_args[0].value = &inarg; 857d5b48543SMiklos Szeredi args.in_args[1].size = entry->d_name.len + 1; 858d5b48543SMiklos Szeredi args.in_args[1].value = entry->d_name.name; 859fcee216bSMax Reitz return create_new_entry(fm, &args, dir, entry, mode); 8609e6268dbSMiklos Szeredi } 8619e6268dbSMiklos Szeredi 8626c960e68SChristian Brauner static int fuse_create(struct mnt_idmap *idmap, struct inode *dir, 863549c7297SChristian Brauner struct dentry *entry, umode_t mode, bool excl) 8649e6268dbSMiklos Szeredi { 8655ebb29beSChristian Brauner return fuse_mknod(&nop_mnt_idmap, dir, entry, mode, 0); 8669e6268dbSMiklos Szeredi } 8679e6268dbSMiklos Szeredi 868011e2b71SChristian Brauner static int fuse_tmpfile(struct mnt_idmap *idmap, struct inode *dir, 8697d375390SMiklos Szeredi struct file *file, umode_t mode) 8707d375390SMiklos Szeredi { 8717d375390SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 8727d375390SMiklos Szeredi int err; 8737d375390SMiklos Szeredi 8747d375390SMiklos Szeredi if (fc->no_tmpfile) 8757d375390SMiklos Szeredi return -EOPNOTSUPP; 8767d375390SMiklos Szeredi 8777d375390SMiklos Szeredi err = fuse_create_open(dir, file->f_path.dentry, file, file->f_flags, mode, FUSE_TMPFILE); 8787d375390SMiklos Szeredi if (err == -ENOSYS) { 8797d375390SMiklos Szeredi fc->no_tmpfile = 1; 8807d375390SMiklos Szeredi err = -EOPNOTSUPP; 8817d375390SMiklos Szeredi } 8827d375390SMiklos Szeredi return err; 8837d375390SMiklos Szeredi } 8847d375390SMiklos Szeredi 885c54bd91eSChristian Brauner static int fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir, 886549c7297SChristian Brauner struct dentry *entry, umode_t mode) 8879e6268dbSMiklos Szeredi { 8889e6268dbSMiklos Szeredi struct fuse_mkdir_in inarg; 889fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(dir); 8907078187aSMiklos Szeredi FUSE_ARGS(args); 8919e6268dbSMiklos Szeredi 892fcee216bSMax Reitz if (!fm->fc->dont_mask) 893e0a43ddcSMiklos Szeredi mode &= ~current_umask(); 894e0a43ddcSMiklos Szeredi 8959e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 8969e6268dbSMiklos Szeredi inarg.mode = mode; 897e0a43ddcSMiklos Szeredi inarg.umask = current_umask(); 898d5b48543SMiklos Szeredi args.opcode = FUSE_MKDIR; 899d5b48543SMiklos Szeredi args.in_numargs = 2; 900d5b48543SMiklos Szeredi args.in_args[0].size = sizeof(inarg); 901d5b48543SMiklos Szeredi args.in_args[0].value = &inarg; 902d5b48543SMiklos Szeredi args.in_args[1].size = entry->d_name.len + 1; 903d5b48543SMiklos Szeredi args.in_args[1].value = entry->d_name.name; 904fcee216bSMax Reitz return create_new_entry(fm, &args, dir, entry, S_IFDIR); 9059e6268dbSMiklos Szeredi } 9069e6268dbSMiklos Szeredi 9077a77db95SChristian Brauner static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir, 908549c7297SChristian Brauner struct dentry *entry, const char *link) 9099e6268dbSMiklos Szeredi { 910fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(dir); 9119e6268dbSMiklos Szeredi unsigned len = strlen(link) + 1; 9127078187aSMiklos Szeredi FUSE_ARGS(args); 9139e6268dbSMiklos Szeredi 914d5b48543SMiklos Szeredi args.opcode = FUSE_SYMLINK; 915d5b48543SMiklos Szeredi args.in_numargs = 2; 916d5b48543SMiklos Szeredi args.in_args[0].size = entry->d_name.len + 1; 917d5b48543SMiklos Szeredi args.in_args[0].value = entry->d_name.name; 918d5b48543SMiklos Szeredi args.in_args[1].size = len; 919d5b48543SMiklos Szeredi args.in_args[1].value = link; 920fcee216bSMax Reitz return create_new_entry(fm, &args, dir, entry, S_IFLNK); 9219e6268dbSMiklos Szeredi } 9229e6268dbSMiklos Szeredi 9235c791fe1SMiklos Szeredi void fuse_flush_time_update(struct inode *inode) 9245c791fe1SMiklos Szeredi { 9255c791fe1SMiklos Szeredi int err = sync_inode_metadata(inode, 1); 9265c791fe1SMiklos Szeredi 9275c791fe1SMiklos Szeredi mapping_set_error(inode->i_mapping, err); 9285c791fe1SMiklos Szeredi } 9295c791fe1SMiklos Szeredi 93097f044f6SMiklos Szeredi static void fuse_update_ctime_in_cache(struct inode *inode) 93131f3267bSMaxim Patlasov { 93231f3267bSMaxim Patlasov if (!IS_NOCMTIME(inode)) { 933ceb2d5e9SJeff Layton inode_set_ctime_current(inode); 93431f3267bSMaxim Patlasov mark_inode_dirty_sync(inode); 9355c791fe1SMiklos Szeredi fuse_flush_time_update(inode); 93631f3267bSMaxim Patlasov } 93731f3267bSMaxim Patlasov } 93831f3267bSMaxim Patlasov 93997f044f6SMiklos Szeredi void fuse_update_ctime(struct inode *inode) 94097f044f6SMiklos Szeredi { 941fa5eee57SMiklos Szeredi fuse_invalidate_attr_mask(inode, STATX_CTIME); 94297f044f6SMiklos Szeredi fuse_update_ctime_in_cache(inode); 94397f044f6SMiklos Szeredi } 94497f044f6SMiklos Szeredi 945cefd1b83SMiklos Szeredi static void fuse_entry_unlinked(struct dentry *entry) 946cefd1b83SMiklos Szeredi { 947cefd1b83SMiklos Szeredi struct inode *inode = d_inode(entry); 948cefd1b83SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 949cefd1b83SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 950cefd1b83SMiklos Szeredi 951cefd1b83SMiklos Szeredi spin_lock(&fi->lock); 952cefd1b83SMiklos Szeredi fi->attr_version = atomic64_inc_return(&fc->attr_version); 953cefd1b83SMiklos Szeredi /* 954cefd1b83SMiklos Szeredi * If i_nlink == 0 then unlink doesn't make sense, yet this can 955cefd1b83SMiklos Szeredi * happen if userspace filesystem is careless. It would be 956cefd1b83SMiklos Szeredi * difficult to enforce correct nlink usage so just ignore this 957cefd1b83SMiklos Szeredi * condition here 958cefd1b83SMiklos Szeredi */ 959cefd1b83SMiklos Szeredi if (S_ISDIR(inode->i_mode)) 960cefd1b83SMiklos Szeredi clear_nlink(inode); 961cefd1b83SMiklos Szeredi else if (inode->i_nlink > 0) 962cefd1b83SMiklos Szeredi drop_nlink(inode); 963cefd1b83SMiklos Szeredi spin_unlock(&fi->lock); 964cefd1b83SMiklos Szeredi fuse_invalidate_entry_cache(entry); 965cefd1b83SMiklos Szeredi fuse_update_ctime(inode); 966cefd1b83SMiklos Szeredi } 967cefd1b83SMiklos Szeredi 9689e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry) 9699e6268dbSMiklos Szeredi { 9709e6268dbSMiklos Szeredi int err; 971fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(dir); 9727078187aSMiklos Szeredi FUSE_ARGS(args); 9739e6268dbSMiklos Szeredi 9745d069dbeSMiklos Szeredi if (fuse_is_bad(dir)) 9755d069dbeSMiklos Szeredi return -EIO; 9765d069dbeSMiklos Szeredi 977d5b48543SMiklos Szeredi args.opcode = FUSE_UNLINK; 978d5b48543SMiklos Szeredi args.nodeid = get_node_id(dir); 979d5b48543SMiklos Szeredi args.in_numargs = 1; 980d5b48543SMiklos Szeredi args.in_args[0].size = entry->d_name.len + 1; 981d5b48543SMiklos Szeredi args.in_args[0].value = entry->d_name.name; 982fcee216bSMax Reitz err = fuse_simple_request(fm, &args); 9839e6268dbSMiklos Szeredi if (!err) { 984261aaba7SMiklos Szeredi fuse_dir_changed(dir); 985cefd1b83SMiklos Szeredi fuse_entry_unlinked(entry); 9867d875e66SJiachen Zhang } else if (err == -EINTR || err == -ENOENT) 9879e6268dbSMiklos Szeredi fuse_invalidate_entry(entry); 9889e6268dbSMiklos Szeredi return err; 9899e6268dbSMiklos Szeredi } 9909e6268dbSMiklos Szeredi 9919e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry) 9929e6268dbSMiklos Szeredi { 9939e6268dbSMiklos Szeredi int err; 994fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(dir); 9957078187aSMiklos Szeredi FUSE_ARGS(args); 9969e6268dbSMiklos Szeredi 9975d069dbeSMiklos Szeredi if (fuse_is_bad(dir)) 9985d069dbeSMiklos Szeredi return -EIO; 9995d069dbeSMiklos Szeredi 1000d5b48543SMiklos Szeredi args.opcode = FUSE_RMDIR; 1001d5b48543SMiklos Szeredi args.nodeid = get_node_id(dir); 1002d5b48543SMiklos Szeredi args.in_numargs = 1; 1003d5b48543SMiklos Szeredi args.in_args[0].size = entry->d_name.len + 1; 1004d5b48543SMiklos Szeredi args.in_args[0].value = entry->d_name.name; 1005fcee216bSMax Reitz err = fuse_simple_request(fm, &args); 10069e6268dbSMiklos Szeredi if (!err) { 1007261aaba7SMiklos Szeredi fuse_dir_changed(dir); 1008cefd1b83SMiklos Szeredi fuse_entry_unlinked(entry); 10097d875e66SJiachen Zhang } else if (err == -EINTR || err == -ENOENT) 10109e6268dbSMiklos Szeredi fuse_invalidate_entry(entry); 10119e6268dbSMiklos Szeredi return err; 10129e6268dbSMiklos Szeredi } 10139e6268dbSMiklos Szeredi 10141560c974SMiklos Szeredi static int fuse_rename_common(struct inode *olddir, struct dentry *oldent, 10151560c974SMiklos Szeredi struct inode *newdir, struct dentry *newent, 10161560c974SMiklos Szeredi unsigned int flags, int opcode, size_t argsize) 10179e6268dbSMiklos Szeredi { 10189e6268dbSMiklos Szeredi int err; 10191560c974SMiklos Szeredi struct fuse_rename2_in inarg; 1020fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(olddir); 10217078187aSMiklos Szeredi FUSE_ARGS(args); 10229e6268dbSMiklos Szeredi 10231560c974SMiklos Szeredi memset(&inarg, 0, argsize); 10249e6268dbSMiklos Szeredi inarg.newdir = get_node_id(newdir); 10251560c974SMiklos Szeredi inarg.flags = flags; 1026d5b48543SMiklos Szeredi args.opcode = opcode; 1027d5b48543SMiklos Szeredi args.nodeid = get_node_id(olddir); 1028d5b48543SMiklos Szeredi args.in_numargs = 3; 1029d5b48543SMiklos Szeredi args.in_args[0].size = argsize; 1030d5b48543SMiklos Szeredi args.in_args[0].value = &inarg; 1031d5b48543SMiklos Szeredi args.in_args[1].size = oldent->d_name.len + 1; 1032d5b48543SMiklos Szeredi args.in_args[1].value = oldent->d_name.name; 1033d5b48543SMiklos Szeredi args.in_args[2].size = newent->d_name.len + 1; 1034d5b48543SMiklos Szeredi args.in_args[2].value = newent->d_name.name; 1035fcee216bSMax Reitz err = fuse_simple_request(fm, &args); 10369e6268dbSMiklos Szeredi if (!err) { 103708b63307SMiklos Szeredi /* ctime changes */ 10382b0143b5SDavid Howells fuse_update_ctime(d_inode(oldent)); 103908b63307SMiklos Szeredi 1040371e8fd0SMiklos Szeredi if (flags & RENAME_EXCHANGE) 10412b0143b5SDavid Howells fuse_update_ctime(d_inode(newent)); 10421560c974SMiklos Szeredi 1043261aaba7SMiklos Szeredi fuse_dir_changed(olddir); 10449e6268dbSMiklos Szeredi if (olddir != newdir) 1045261aaba7SMiklos Szeredi fuse_dir_changed(newdir); 10468cbdf1e6SMiklos Szeredi 10478cbdf1e6SMiklos Szeredi /* newent will end up negative */ 1048cefd1b83SMiklos Szeredi if (!(flags & RENAME_EXCHANGE) && d_really_is_positive(newent)) 1049cefd1b83SMiklos Szeredi fuse_entry_unlinked(newent); 10507d875e66SJiachen Zhang } else if (err == -EINTR || err == -ENOENT) { 10519e6268dbSMiklos Szeredi /* If request was interrupted, DEITY only knows if the 10529e6268dbSMiklos Szeredi rename actually took place. If the invalidation 10539e6268dbSMiklos Szeredi fails (e.g. some process has CWD under the renamed 10549e6268dbSMiklos Szeredi directory), then there can be inconsistency between 10559e6268dbSMiklos Szeredi the dcache and the real filesystem. Tough luck. */ 10569e6268dbSMiklos Szeredi fuse_invalidate_entry(oldent); 10572b0143b5SDavid Howells if (d_really_is_positive(newent)) 10589e6268dbSMiklos Szeredi fuse_invalidate_entry(newent); 10599e6268dbSMiklos Szeredi } 10609e6268dbSMiklos Szeredi 10619e6268dbSMiklos Szeredi return err; 10629e6268dbSMiklos Szeredi } 10639e6268dbSMiklos Szeredi 1064e18275aeSChristian Brauner static int fuse_rename2(struct mnt_idmap *idmap, struct inode *olddir, 1065549c7297SChristian Brauner struct dentry *oldent, struct inode *newdir, 1066549c7297SChristian Brauner struct dentry *newent, unsigned int flags) 10671560c974SMiklos Szeredi { 10681560c974SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(olddir); 10691560c974SMiklos Szeredi int err; 10701560c974SMiklos Szeredi 10715d069dbeSMiklos Szeredi if (fuse_is_bad(olddir)) 10725d069dbeSMiklos Szeredi return -EIO; 10735d069dbeSMiklos Szeredi 1074519525faSVivek Goyal if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) 10751560c974SMiklos Szeredi return -EINVAL; 10761560c974SMiklos Szeredi 10774237ba43SMiklos Szeredi if (flags) { 10781560c974SMiklos Szeredi if (fc->no_rename2 || fc->minor < 23) 10791560c974SMiklos Szeredi return -EINVAL; 10801560c974SMiklos Szeredi 10811560c974SMiklos Szeredi err = fuse_rename_common(olddir, oldent, newdir, newent, flags, 10824237ba43SMiklos Szeredi FUSE_RENAME2, 10834237ba43SMiklos Szeredi sizeof(struct fuse_rename2_in)); 10841560c974SMiklos Szeredi if (err == -ENOSYS) { 10851560c974SMiklos Szeredi fc->no_rename2 = 1; 10861560c974SMiklos Szeredi err = -EINVAL; 10871560c974SMiklos Szeredi } 10884237ba43SMiklos Szeredi } else { 10894237ba43SMiklos Szeredi err = fuse_rename_common(olddir, oldent, newdir, newent, 0, 10904237ba43SMiklos Szeredi FUSE_RENAME, 10914237ba43SMiklos Szeredi sizeof(struct fuse_rename_in)); 10924237ba43SMiklos Szeredi } 10931560c974SMiklos Szeredi 10944237ba43SMiklos Szeredi return err; 10954237ba43SMiklos Szeredi } 10964237ba43SMiklos Szeredi 10979e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir, 10989e6268dbSMiklos Szeredi struct dentry *newent) 10999e6268dbSMiklos Szeredi { 11009e6268dbSMiklos Szeredi int err; 11019e6268dbSMiklos Szeredi struct fuse_link_in inarg; 11022b0143b5SDavid Howells struct inode *inode = d_inode(entry); 1103fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(inode); 11047078187aSMiklos Szeredi FUSE_ARGS(args); 11059e6268dbSMiklos Szeredi 11069e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 11079e6268dbSMiklos Szeredi inarg.oldnodeid = get_node_id(inode); 1108d5b48543SMiklos Szeredi args.opcode = FUSE_LINK; 1109d5b48543SMiklos Szeredi args.in_numargs = 2; 1110d5b48543SMiklos Szeredi args.in_args[0].size = sizeof(inarg); 1111d5b48543SMiklos Szeredi args.in_args[0].value = &inarg; 1112d5b48543SMiklos Szeredi args.in_args[1].size = newent->d_name.len + 1; 1113d5b48543SMiklos Szeredi args.in_args[1].value = newent->d_name.name; 1114fcee216bSMax Reitz err = create_new_entry(fm, &args, newdir, newent, inode->i_mode); 111597f044f6SMiklos Szeredi if (!err) 111697f044f6SMiklos Szeredi fuse_update_ctime_in_cache(inode); 111797f044f6SMiklos Szeredi else if (err == -EINTR) 1118ac45d613SMiklos Szeredi fuse_invalidate_attr(inode); 111997f044f6SMiklos Szeredi 11209e6268dbSMiklos Szeredi return err; 11219e6268dbSMiklos Szeredi } 11229e6268dbSMiklos Szeredi 11231fb69e78SMiklos Szeredi static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, 11241fb69e78SMiklos Szeredi struct kstat *stat) 11251fb69e78SMiklos Szeredi { 1126203627bbSMiklos Szeredi unsigned int blkbits; 11278373200bSPavel Emelyanov struct fuse_conn *fc = get_fuse_conn(inode); 11288373200bSPavel Emelyanov 11291fb69e78SMiklos Szeredi stat->dev = inode->i_sb->s_dev; 11301fb69e78SMiklos Szeredi stat->ino = attr->ino; 11311fb69e78SMiklos Szeredi stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); 11321fb69e78SMiklos Szeredi stat->nlink = attr->nlink; 11338cb08329SEric W. Biederman stat->uid = make_kuid(fc->user_ns, attr->uid); 11348cb08329SEric W. Biederman stat->gid = make_kgid(fc->user_ns, attr->gid); 11351fb69e78SMiklos Szeredi stat->rdev = inode->i_rdev; 11361fb69e78SMiklos Szeredi stat->atime.tv_sec = attr->atime; 11371fb69e78SMiklos Szeredi stat->atime.tv_nsec = attr->atimensec; 11381fb69e78SMiklos Szeredi stat->mtime.tv_sec = attr->mtime; 11391fb69e78SMiklos Szeredi stat->mtime.tv_nsec = attr->mtimensec; 11401fb69e78SMiklos Szeredi stat->ctime.tv_sec = attr->ctime; 11411fb69e78SMiklos Szeredi stat->ctime.tv_nsec = attr->ctimensec; 11421fb69e78SMiklos Szeredi stat->size = attr->size; 11431fb69e78SMiklos Szeredi stat->blocks = attr->blocks; 1144203627bbSMiklos Szeredi 1145203627bbSMiklos Szeredi if (attr->blksize != 0) 1146203627bbSMiklos Szeredi blkbits = ilog2(attr->blksize); 1147203627bbSMiklos Szeredi else 1148203627bbSMiklos Szeredi blkbits = inode->i_sb->s_blocksize_bits; 1149203627bbSMiklos Szeredi 1150203627bbSMiklos Szeredi stat->blksize = 1 << blkbits; 11511fb69e78SMiklos Szeredi } 11521fb69e78SMiklos Szeredi 1153d3045530SMiklos Szeredi static void fuse_statx_to_attr(struct fuse_statx *sx, struct fuse_attr *attr) 1154d3045530SMiklos Szeredi { 1155d3045530SMiklos Szeredi memset(attr, 0, sizeof(*attr)); 1156d3045530SMiklos Szeredi attr->ino = sx->ino; 1157d3045530SMiklos Szeredi attr->size = sx->size; 1158d3045530SMiklos Szeredi attr->blocks = sx->blocks; 1159d3045530SMiklos Szeredi attr->atime = sx->atime.tv_sec; 1160d3045530SMiklos Szeredi attr->mtime = sx->mtime.tv_sec; 1161d3045530SMiklos Szeredi attr->ctime = sx->ctime.tv_sec; 1162d3045530SMiklos Szeredi attr->atimensec = sx->atime.tv_nsec; 1163d3045530SMiklos Szeredi attr->mtimensec = sx->mtime.tv_nsec; 1164d3045530SMiklos Szeredi attr->ctimensec = sx->ctime.tv_nsec; 1165d3045530SMiklos Szeredi attr->mode = sx->mode; 1166d3045530SMiklos Szeredi attr->nlink = sx->nlink; 1167d3045530SMiklos Szeredi attr->uid = sx->uid; 1168d3045530SMiklos Szeredi attr->gid = sx->gid; 1169d3045530SMiklos Szeredi attr->rdev = new_encode_dev(MKDEV(sx->rdev_major, sx->rdev_minor)); 1170d3045530SMiklos Szeredi attr->blksize = sx->blksize; 1171d3045530SMiklos Szeredi } 1172d3045530SMiklos Szeredi 1173d3045530SMiklos Szeredi static int fuse_do_statx(struct inode *inode, struct file *file, 1174d3045530SMiklos Szeredi struct kstat *stat) 1175d3045530SMiklos Szeredi { 1176d3045530SMiklos Szeredi int err; 1177d3045530SMiklos Szeredi struct fuse_attr attr; 1178d3045530SMiklos Szeredi struct fuse_statx *sx; 1179d3045530SMiklos Szeredi struct fuse_statx_in inarg; 1180d3045530SMiklos Szeredi struct fuse_statx_out outarg; 1181d3045530SMiklos Szeredi struct fuse_mount *fm = get_fuse_mount(inode); 1182d3045530SMiklos Szeredi u64 attr_version = fuse_get_attr_version(fm->fc); 1183d3045530SMiklos Szeredi FUSE_ARGS(args); 1184d3045530SMiklos Szeredi 1185d3045530SMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 1186d3045530SMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 1187d3045530SMiklos Szeredi /* Directories have separate file-handle space */ 1188d3045530SMiklos Szeredi if (file && S_ISREG(inode->i_mode)) { 1189d3045530SMiklos Szeredi struct fuse_file *ff = file->private_data; 1190d3045530SMiklos Szeredi 1191d3045530SMiklos Szeredi inarg.getattr_flags |= FUSE_GETATTR_FH; 1192d3045530SMiklos Szeredi inarg.fh = ff->fh; 1193d3045530SMiklos Szeredi } 1194d3045530SMiklos Szeredi /* For now leave sync hints as the default, request all stats. */ 1195d3045530SMiklos Szeredi inarg.sx_flags = 0; 1196d3045530SMiklos Szeredi inarg.sx_mask = STATX_BASIC_STATS | STATX_BTIME; 1197d3045530SMiklos Szeredi args.opcode = FUSE_STATX; 1198d3045530SMiklos Szeredi args.nodeid = get_node_id(inode); 1199d3045530SMiklos Szeredi args.in_numargs = 1; 1200d3045530SMiklos Szeredi args.in_args[0].size = sizeof(inarg); 1201d3045530SMiklos Szeredi args.in_args[0].value = &inarg; 1202d3045530SMiklos Szeredi args.out_numargs = 1; 1203d3045530SMiklos Szeredi args.out_args[0].size = sizeof(outarg); 1204d3045530SMiklos Szeredi args.out_args[0].value = &outarg; 1205d3045530SMiklos Szeredi err = fuse_simple_request(fm, &args); 1206d3045530SMiklos Szeredi if (err) 1207d3045530SMiklos Szeredi return err; 1208d3045530SMiklos Szeredi 1209d3045530SMiklos Szeredi sx = &outarg.stat; 1210d3045530SMiklos Szeredi if (((sx->mask & STATX_SIZE) && !fuse_valid_size(sx->size)) || 1211d3045530SMiklos Szeredi ((sx->mask & STATX_TYPE) && (!fuse_valid_type(sx->mode) || 1212d3045530SMiklos Szeredi inode_wrong_type(inode, sx->mode)))) { 1213*3d304dd6SMiklos Szeredi fuse_make_bad(inode); 1214d3045530SMiklos Szeredi return -EIO; 1215d3045530SMiklos Szeredi } 1216d3045530SMiklos Szeredi 1217d3045530SMiklos Szeredi fuse_statx_to_attr(&outarg.stat, &attr); 1218d3045530SMiklos Szeredi if ((sx->mask & STATX_BASIC_STATS) == STATX_BASIC_STATS) { 1219972f4c46SMiklos Szeredi fuse_change_attributes(inode, &attr, &outarg.stat, 1220972f4c46SMiklos Szeredi ATTR_TIMEOUT(&outarg), attr_version); 1221d3045530SMiklos Szeredi } 1222f73016b6SBernd Schubert 1223f73016b6SBernd Schubert if (stat) { 1224d3045530SMiklos Szeredi stat->result_mask = sx->mask & (STATX_BASIC_STATS | STATX_BTIME); 1225d3045530SMiklos Szeredi stat->btime.tv_sec = sx->btime.tv_sec; 1226d3045530SMiklos Szeredi stat->btime.tv_nsec = min_t(u32, sx->btime.tv_nsec, NSEC_PER_SEC - 1); 1227d3045530SMiklos Szeredi fuse_fillattr(inode, &attr, stat); 1228d3045530SMiklos Szeredi stat->result_mask |= STATX_TYPE; 1229f73016b6SBernd Schubert } 1230d3045530SMiklos Szeredi 1231d3045530SMiklos Szeredi return 0; 1232d3045530SMiklos Szeredi } 1233d3045530SMiklos Szeredi 1234c79e322fSMiklos Szeredi static int fuse_do_getattr(struct inode *inode, struct kstat *stat, 1235c79e322fSMiklos Szeredi struct file *file) 1236e5e5558eSMiklos Szeredi { 1237e5e5558eSMiklos Szeredi int err; 1238c79e322fSMiklos Szeredi struct fuse_getattr_in inarg; 1239c79e322fSMiklos Szeredi struct fuse_attr_out outarg; 1240fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(inode); 12417078187aSMiklos Szeredi FUSE_ARGS(args); 12421fb69e78SMiklos Szeredi u64 attr_version; 12431fb69e78SMiklos Szeredi 1244fcee216bSMax Reitz attr_version = fuse_get_attr_version(fm->fc); 12451fb69e78SMiklos Szeredi 1246c79e322fSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 12470e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 1248c79e322fSMiklos Szeredi /* Directories have separate file-handle space */ 1249c79e322fSMiklos Szeredi if (file && S_ISREG(inode->i_mode)) { 1250c79e322fSMiklos Szeredi struct fuse_file *ff = file->private_data; 1251c79e322fSMiklos Szeredi 1252c79e322fSMiklos Szeredi inarg.getattr_flags |= FUSE_GETATTR_FH; 1253c79e322fSMiklos Szeredi inarg.fh = ff->fh; 1254c79e322fSMiklos Szeredi } 1255d5b48543SMiklos Szeredi args.opcode = FUSE_GETATTR; 1256d5b48543SMiklos Szeredi args.nodeid = get_node_id(inode); 1257d5b48543SMiklos Szeredi args.in_numargs = 1; 1258d5b48543SMiklos Szeredi args.in_args[0].size = sizeof(inarg); 1259d5b48543SMiklos Szeredi args.in_args[0].value = &inarg; 1260d5b48543SMiklos Szeredi args.out_numargs = 1; 1261d5b48543SMiklos Szeredi args.out_args[0].size = sizeof(outarg); 1262d5b48543SMiklos Szeredi args.out_args[0].value = &outarg; 1263fcee216bSMax Reitz err = fuse_simple_request(fm, &args); 1264e5e5558eSMiklos Szeredi if (!err) { 1265eb59bd17SMiklos Szeredi if (fuse_invalid_attr(&outarg.attr) || 12666e3e2c43SAl Viro inode_wrong_type(inode, outarg.attr.mode)) { 12675d069dbeSMiklos Szeredi fuse_make_bad(inode); 1268e5e5558eSMiklos Szeredi err = -EIO; 1269e5e5558eSMiklos Szeredi } else { 1270972f4c46SMiklos Szeredi fuse_change_attributes(inode, &outarg.attr, NULL, 12719dc10a54SMiklos Szeredi ATTR_TIMEOUT(&outarg), 12721fb69e78SMiklos Szeredi attr_version); 12731fb69e78SMiklos Szeredi if (stat) 1274c79e322fSMiklos Szeredi fuse_fillattr(inode, &outarg.attr, stat); 1275e5e5558eSMiklos Szeredi } 1276e5e5558eSMiklos Szeredi } 1277e5e5558eSMiklos Szeredi return err; 1278e5e5558eSMiklos Szeredi } 1279e5e5558eSMiklos Szeredi 12805b97eeacSMiklos Szeredi static int fuse_update_get_attr(struct inode *inode, struct file *file, 12812f1e8196SMiklos Szeredi struct kstat *stat, u32 request_mask, 12822f1e8196SMiklos Szeredi unsigned int flags) 1283bcb4be80SMiklos Szeredi { 1284bcb4be80SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 1285d3045530SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 12865b97eeacSMiklos Szeredi int err = 0; 1287bf5c1898SMiklos Szeredi bool sync; 1288ec855375SMiklos Szeredi u32 inval_mask = READ_ONCE(fi->inval_mask); 1289ec855375SMiklos Szeredi u32 cache_mask = fuse_get_cache_mask(inode); 1290bcb4be80SMiklos Szeredi 1291d3045530SMiklos Szeredi 1292d3045530SMiklos Szeredi /* FUSE only supports basic stats and possibly btime */ 1293d3045530SMiklos Szeredi request_mask &= STATX_BASIC_STATS | STATX_BTIME; 1294d3045530SMiklos Szeredi retry: 1295d3045530SMiklos Szeredi if (fc->no_statx) 12968d8f9c4bSMiklos Szeredi request_mask &= STATX_BASIC_STATS; 12978d8f9c4bSMiklos Szeredi 12988d8f9c4bSMiklos Szeredi if (!request_mask) 12998d8f9c4bSMiklos Szeredi sync = false; 13008d8f9c4bSMiklos Szeredi else if (flags & AT_STATX_FORCE_SYNC) 1301bf5c1898SMiklos Szeredi sync = true; 1302bf5c1898SMiklos Szeredi else if (flags & AT_STATX_DONT_SYNC) 1303bf5c1898SMiklos Szeredi sync = false; 1304ec855375SMiklos Szeredi else if (request_mask & inval_mask & ~cache_mask) 13052f1e8196SMiklos Szeredi sync = true; 1306bf5c1898SMiklos Szeredi else 1307bf5c1898SMiklos Szeredi sync = time_before64(fi->i_time, get_jiffies_64()); 1308bf5c1898SMiklos Szeredi 1309bf5c1898SMiklos Szeredi if (sync) { 131060bcc88aSSeth Forshee forget_all_cached_acls(inode); 1311d3045530SMiklos Szeredi /* Try statx if BTIME is requested */ 1312d3045530SMiklos Szeredi if (!fc->no_statx && (request_mask & ~STATX_BASIC_STATS)) { 1313d3045530SMiklos Szeredi err = fuse_do_statx(inode, file, stat); 1314d3045530SMiklos Szeredi if (err == -ENOSYS) { 1315d3045530SMiklos Szeredi fc->no_statx = 1; 1316d3045530SMiklos Szeredi goto retry; 1317d3045530SMiklos Szeredi } 1318d3045530SMiklos Szeredi } else { 1319bcb4be80SMiklos Szeredi err = fuse_do_getattr(inode, stat, file); 1320d3045530SMiklos Szeredi } 13215b97eeacSMiklos Szeredi } else if (stat) { 13220d72b928SJeff Layton generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat); 1323bcb4be80SMiklos Szeredi stat->mode = fi->orig_i_mode; 132445c72cd7SPavel Shilovsky stat->ino = fi->orig_ino; 1325972f4c46SMiklos Szeredi if (test_bit(FUSE_I_BTIME, &fi->state)) { 1326972f4c46SMiklos Szeredi stat->btime = fi->i_btime; 1327972f4c46SMiklos Szeredi stat->result_mask |= STATX_BTIME; 1328972f4c46SMiklos Szeredi } 1329bcb4be80SMiklos Szeredi } 1330bcb4be80SMiklos Szeredi 1331bcb4be80SMiklos Szeredi return err; 1332bcb4be80SMiklos Szeredi } 1333bcb4be80SMiklos Szeredi 1334c6c745b8SMiklos Szeredi int fuse_update_attributes(struct inode *inode, struct file *file, u32 mask) 13355b97eeacSMiklos Szeredi { 1336c6c745b8SMiklos Szeredi return fuse_update_get_attr(inode, file, NULL, mask, 0); 13375b97eeacSMiklos Szeredi } 13385b97eeacSMiklos Szeredi 1339fcee216bSMax Reitz int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid, 13404f8d3702SMiklos Szeredi u64 child_nodeid, struct qstr *name, u32 flags) 13413b463ae0SJohn Muir { 13423b463ae0SJohn Muir int err = -ENOTDIR; 13433b463ae0SJohn Muir struct inode *parent; 13443b463ae0SJohn Muir struct dentry *dir; 13453b463ae0SJohn Muir struct dentry *entry; 13463b463ae0SJohn Muir 1347fcee216bSMax Reitz parent = fuse_ilookup(fc, parent_nodeid, NULL); 13483b463ae0SJohn Muir if (!parent) 13493b463ae0SJohn Muir return -ENOENT; 13503b463ae0SJohn Muir 1351bda9a719SMiklos Szeredi inode_lock_nested(parent, I_MUTEX_PARENT); 13523b463ae0SJohn Muir if (!S_ISDIR(parent->i_mode)) 13533b463ae0SJohn Muir goto unlock; 13543b463ae0SJohn Muir 13553b463ae0SJohn Muir err = -ENOENT; 13563b463ae0SJohn Muir dir = d_find_alias(parent); 13573b463ae0SJohn Muir if (!dir) 13583b463ae0SJohn Muir goto unlock; 13593b463ae0SJohn Muir 13608387ff25SLinus Torvalds name->hash = full_name_hash(dir, name->name, name->len); 13613b463ae0SJohn Muir entry = d_lookup(dir, name); 13623b463ae0SJohn Muir dput(dir); 13633b463ae0SJohn Muir if (!entry) 13643b463ae0SJohn Muir goto unlock; 13653b463ae0SJohn Muir 1366261aaba7SMiklos Szeredi fuse_dir_changed(parent); 13674f8d3702SMiklos Szeredi if (!(flags & FUSE_EXPIRE_ONLY)) 13684f8d3702SMiklos Szeredi d_invalidate(entry); 13694f8d3702SMiklos Szeredi fuse_invalidate_entry_cache(entry); 1370451d0f59SJohn Muir 13712b0143b5SDavid Howells if (child_nodeid != 0 && d_really_is_positive(entry)) { 13725955102cSAl Viro inode_lock(d_inode(entry)); 13732b0143b5SDavid Howells if (get_node_id(d_inode(entry)) != child_nodeid) { 1374451d0f59SJohn Muir err = -ENOENT; 1375451d0f59SJohn Muir goto badentry; 1376451d0f59SJohn Muir } 1377451d0f59SJohn Muir if (d_mountpoint(entry)) { 1378451d0f59SJohn Muir err = -EBUSY; 1379451d0f59SJohn Muir goto badentry; 1380451d0f59SJohn Muir } 1381e36cb0b8SDavid Howells if (d_is_dir(entry)) { 1382451d0f59SJohn Muir shrink_dcache_parent(entry); 1383451d0f59SJohn Muir if (!simple_empty(entry)) { 1384451d0f59SJohn Muir err = -ENOTEMPTY; 1385451d0f59SJohn Muir goto badentry; 1386451d0f59SJohn Muir } 13872b0143b5SDavid Howells d_inode(entry)->i_flags |= S_DEAD; 1388451d0f59SJohn Muir } 1389451d0f59SJohn Muir dont_mount(entry); 13902b0143b5SDavid Howells clear_nlink(d_inode(entry)); 13913b463ae0SJohn Muir err = 0; 1392451d0f59SJohn Muir badentry: 13935955102cSAl Viro inode_unlock(d_inode(entry)); 1394451d0f59SJohn Muir if (!err) 1395451d0f59SJohn Muir d_delete(entry); 1396451d0f59SJohn Muir } else { 1397451d0f59SJohn Muir err = 0; 1398451d0f59SJohn Muir } 1399451d0f59SJohn Muir dput(entry); 14003b463ae0SJohn Muir 14013b463ae0SJohn Muir unlock: 14025955102cSAl Viro inode_unlock(parent); 14033b463ae0SJohn Muir iput(parent); 14043b463ae0SJohn Muir return err; 14053b463ae0SJohn Muir } 14063b463ae0SJohn Muir 1407b1387777SDave Marchevsky static inline bool fuse_permissible_uidgid(struct fuse_conn *fc) 1408b1387777SDave Marchevsky { 1409b1387777SDave Marchevsky const struct cred *cred = current_cred(); 1410b1387777SDave Marchevsky 1411b1387777SDave Marchevsky return (uid_eq(cred->euid, fc->user_id) && 1412b1387777SDave Marchevsky uid_eq(cred->suid, fc->user_id) && 1413b1387777SDave Marchevsky uid_eq(cred->uid, fc->user_id) && 1414b1387777SDave Marchevsky gid_eq(cred->egid, fc->group_id) && 1415b1387777SDave Marchevsky gid_eq(cred->sgid, fc->group_id) && 1416b1387777SDave Marchevsky gid_eq(cred->gid, fc->group_id)); 1417b1387777SDave Marchevsky } 1418b1387777SDave Marchevsky 141987729a55SMiklos Szeredi /* 142087729a55SMiklos Szeredi * Calling into a user-controlled filesystem gives the filesystem 1421c2132c1bSAnatol Pomozov * daemon ptrace-like capabilities over the current process. This 142287729a55SMiklos Szeredi * means, that the filesystem daemon is able to record the exact 142387729a55SMiklos Szeredi * filesystem operations performed, and can also control the behavior 142487729a55SMiklos Szeredi * of the requester process in otherwise impossible ways. For example 142587729a55SMiklos Szeredi * it can delay the operation for arbitrary length of time allowing 142687729a55SMiklos Szeredi * DoS against the requester. 142787729a55SMiklos Szeredi * 142887729a55SMiklos Szeredi * For this reason only those processes can call into the filesystem, 142987729a55SMiklos Szeredi * for which the owner of the mount has ptrace privilege. This 143087729a55SMiklos Szeredi * excludes processes started by other users, suid or sgid processes. 143187729a55SMiklos Szeredi */ 1432b1387777SDave Marchevsky bool fuse_allow_current_process(struct fuse_conn *fc) 143387729a55SMiklos Szeredi { 1434b1387777SDave Marchevsky bool allow; 14359ccf47b2SDave Marchevsky 143629433a29SMiklos Szeredi if (fc->allow_other) 1437b1387777SDave Marchevsky allow = current_in_userns(fc->user_ns); 1438b1387777SDave Marchevsky else 1439b1387777SDave Marchevsky allow = fuse_permissible_uidgid(fc); 144087729a55SMiklos Szeredi 1441b1387777SDave Marchevsky if (!allow && allow_sys_admin_access && capable(CAP_SYS_ADMIN)) 1442b1387777SDave Marchevsky allow = true; 144387729a55SMiklos Szeredi 1444b1387777SDave Marchevsky return allow; 144587729a55SMiklos Szeredi } 144687729a55SMiklos Szeredi 144731d40d74SMiklos Szeredi static int fuse_access(struct inode *inode, int mask) 144831d40d74SMiklos Szeredi { 1449fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(inode); 14507078187aSMiklos Szeredi FUSE_ARGS(args); 145131d40d74SMiklos Szeredi struct fuse_access_in inarg; 145231d40d74SMiklos Szeredi int err; 145331d40d74SMiklos Szeredi 1454698fa1d1SMiklos Szeredi BUG_ON(mask & MAY_NOT_BLOCK); 1455698fa1d1SMiklos Szeredi 1456fcee216bSMax Reitz if (fm->fc->no_access) 145731d40d74SMiklos Szeredi return 0; 145831d40d74SMiklos Szeredi 145931d40d74SMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 1460e6305c43SAl Viro inarg.mask = mask & (MAY_READ | MAY_WRITE | MAY_EXEC); 1461d5b48543SMiklos Szeredi args.opcode = FUSE_ACCESS; 1462d5b48543SMiklos Szeredi args.nodeid = get_node_id(inode); 1463d5b48543SMiklos Szeredi args.in_numargs = 1; 1464d5b48543SMiklos Szeredi args.in_args[0].size = sizeof(inarg); 1465d5b48543SMiklos Szeredi args.in_args[0].value = &inarg; 1466fcee216bSMax Reitz err = fuse_simple_request(fm, &args); 146731d40d74SMiklos Szeredi if (err == -ENOSYS) { 1468fcee216bSMax Reitz fm->fc->no_access = 1; 146931d40d74SMiklos Szeredi err = 0; 147031d40d74SMiklos Szeredi } 147131d40d74SMiklos Szeredi return err; 147231d40d74SMiklos Szeredi } 147331d40d74SMiklos Szeredi 147410556cb2SAl Viro static int fuse_perm_getattr(struct inode *inode, int mask) 147519690ddbSMiklos Szeredi { 147610556cb2SAl Viro if (mask & MAY_NOT_BLOCK) 147719690ddbSMiklos Szeredi return -ECHILD; 147819690ddbSMiklos Szeredi 147960bcc88aSSeth Forshee forget_all_cached_acls(inode); 148019690ddbSMiklos Szeredi return fuse_do_getattr(inode, NULL, NULL); 148119690ddbSMiklos Szeredi } 148219690ddbSMiklos Szeredi 14836f9f1180SMiklos Szeredi /* 14846f9f1180SMiklos Szeredi * Check permission. The two basic access models of FUSE are: 14856f9f1180SMiklos Szeredi * 14866f9f1180SMiklos Szeredi * 1) Local access checking ('default_permissions' mount option) based 14876f9f1180SMiklos Szeredi * on file mode. This is the plain old disk filesystem permission 14886f9f1180SMiklos Szeredi * modell. 14896f9f1180SMiklos Szeredi * 14906f9f1180SMiklos Szeredi * 2) "Remote" access checking, where server is responsible for 14916f9f1180SMiklos Szeredi * checking permission in each inode operation. An exception to this 14926f9f1180SMiklos Szeredi * is if ->permission() was invoked from sys_access() in which case an 14936f9f1180SMiklos Szeredi * access request is sent. Execute permission is still checked 14946f9f1180SMiklos Szeredi * locally based on file mode. 14956f9f1180SMiklos Szeredi */ 14964609e1f1SChristian Brauner static int fuse_permission(struct mnt_idmap *idmap, 1497549c7297SChristian Brauner struct inode *inode, int mask) 1498e5e5558eSMiklos Szeredi { 1499e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1500244f6385SMiklos Szeredi bool refreshed = false; 1501244f6385SMiklos Szeredi int err = 0; 1502e5e5558eSMiklos Szeredi 15035d069dbeSMiklos Szeredi if (fuse_is_bad(inode)) 15045d069dbeSMiklos Szeredi return -EIO; 15055d069dbeSMiklos Szeredi 1506c2132c1bSAnatol Pomozov if (!fuse_allow_current_process(fc)) 1507e5e5558eSMiklos Szeredi return -EACCES; 1508244f6385SMiklos Szeredi 1509244f6385SMiklos Szeredi /* 1510e8e96157SMiklos Szeredi * If attributes are needed, refresh them before proceeding 1511244f6385SMiklos Szeredi */ 151229433a29SMiklos Szeredi if (fc->default_permissions || 1513e8e96157SMiklos Szeredi ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { 151419690ddbSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 1515d233c7ddSMiklos Szeredi u32 perm_mask = STATX_MODE | STATX_UID | STATX_GID; 151619690ddbSMiklos Szeredi 1517d233c7ddSMiklos Szeredi if (perm_mask & READ_ONCE(fi->inval_mask) || 1518d233c7ddSMiklos Szeredi time_before64(fi->i_time, get_jiffies_64())) { 151919690ddbSMiklos Szeredi refreshed = true; 152019690ddbSMiklos Szeredi 152110556cb2SAl Viro err = fuse_perm_getattr(inode, mask); 1522244f6385SMiklos Szeredi if (err) 1523244f6385SMiklos Szeredi return err; 15241fb69e78SMiklos Szeredi } 152519690ddbSMiklos Szeredi } 1526244f6385SMiklos Szeredi 152729433a29SMiklos Szeredi if (fc->default_permissions) { 15284609e1f1SChristian Brauner err = generic_permission(&nop_mnt_idmap, inode, mask); 15291e9a4ed9SMiklos Szeredi 15301e9a4ed9SMiklos Szeredi /* If permission is denied, try to refresh file 15311e9a4ed9SMiklos Szeredi attributes. This is also needed, because the root 15321e9a4ed9SMiklos Szeredi node will at first have no permissions */ 1533244f6385SMiklos Szeredi if (err == -EACCES && !refreshed) { 153410556cb2SAl Viro err = fuse_perm_getattr(inode, mask); 15351e9a4ed9SMiklos Szeredi if (!err) 15364609e1f1SChristian Brauner err = generic_permission(&nop_mnt_idmap, 153747291baaSChristian Brauner inode, mask); 15381e9a4ed9SMiklos Szeredi } 15391e9a4ed9SMiklos Szeredi 15406f9f1180SMiklos Szeredi /* Note: the opposite of the above test does not 15416f9f1180SMiklos Szeredi exist. So if permissions are revoked this won't be 15426f9f1180SMiklos Szeredi noticed immediately, only after the attribute 15436f9f1180SMiklos Szeredi timeout has expired */ 15449cfcac81SEric Paris } else if (mask & (MAY_ACCESS | MAY_CHDIR)) { 1545e8e96157SMiklos Szeredi err = fuse_access(inode, mask); 1546e8e96157SMiklos Szeredi } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { 1547e8e96157SMiklos Szeredi if (!(inode->i_mode & S_IXUGO)) { 1548e8e96157SMiklos Szeredi if (refreshed) 1549e5e5558eSMiklos Szeredi return -EACCES; 155031d40d74SMiklos Szeredi 155110556cb2SAl Viro err = fuse_perm_getattr(inode, mask); 1552e8e96157SMiklos Szeredi if (!err && !(inode->i_mode & S_IXUGO)) 1553e8e96157SMiklos Szeredi return -EACCES; 1554e8e96157SMiklos Szeredi } 1555e5e5558eSMiklos Szeredi } 1556244f6385SMiklos Szeredi return err; 1557e5e5558eSMiklos Szeredi } 1558e5e5558eSMiklos Szeredi 15595571f1e6SDan Schatzberg static int fuse_readlink_page(struct inode *inode, struct page *page) 1560e5e5558eSMiklos Szeredi { 1561fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(inode); 15624c29afecSMiklos Szeredi struct fuse_page_desc desc = { .length = PAGE_SIZE - 1 }; 15634c29afecSMiklos Szeredi struct fuse_args_pages ap = { 15644c29afecSMiklos Szeredi .num_pages = 1, 15654c29afecSMiklos Szeredi .pages = &page, 15664c29afecSMiklos Szeredi .descs = &desc, 15674c29afecSMiklos Szeredi }; 15684c29afecSMiklos Szeredi char *link; 15694c29afecSMiklos Szeredi ssize_t res; 1570e5e5558eSMiklos Szeredi 15714c29afecSMiklos Szeredi ap.args.opcode = FUSE_READLINK; 15724c29afecSMiklos Szeredi ap.args.nodeid = get_node_id(inode); 15734c29afecSMiklos Szeredi ap.args.out_pages = true; 15744c29afecSMiklos Szeredi ap.args.out_argvar = true; 15754c29afecSMiklos Szeredi ap.args.page_zeroing = true; 15764c29afecSMiklos Szeredi ap.args.out_numargs = 1; 15774c29afecSMiklos Szeredi ap.args.out_args[0].size = desc.length; 1578fcee216bSMax Reitz res = fuse_simple_request(fm, &ap.args); 15796b255391SAl Viro 1580451418fcSAndrew Gallagher fuse_invalidate_atime(inode); 15815571f1e6SDan Schatzberg 15824c29afecSMiklos Szeredi if (res < 0) 15834c29afecSMiklos Szeredi return res; 15844c29afecSMiklos Szeredi 15854c29afecSMiklos Szeredi if (WARN_ON(res >= PAGE_SIZE)) 15864c29afecSMiklos Szeredi return -EIO; 15874c29afecSMiklos Szeredi 15884c29afecSMiklos Szeredi link = page_address(page); 15894c29afecSMiklos Szeredi link[res] = '\0'; 15904c29afecSMiklos Szeredi 15914c29afecSMiklos Szeredi return 0; 15925571f1e6SDan Schatzberg } 15935571f1e6SDan Schatzberg 15945571f1e6SDan Schatzberg static const char *fuse_get_link(struct dentry *dentry, struct inode *inode, 15955571f1e6SDan Schatzberg struct delayed_call *callback) 15965571f1e6SDan Schatzberg { 15975571f1e6SDan Schatzberg struct fuse_conn *fc = get_fuse_conn(inode); 15985571f1e6SDan Schatzberg struct page *page; 15995571f1e6SDan Schatzberg int err; 16005571f1e6SDan Schatzberg 16015571f1e6SDan Schatzberg err = -EIO; 16025d069dbeSMiklos Szeredi if (fuse_is_bad(inode)) 16035571f1e6SDan Schatzberg goto out_err; 16045571f1e6SDan Schatzberg 16055571f1e6SDan Schatzberg if (fc->cache_symlinks) 16065571f1e6SDan Schatzberg return page_get_link(dentry, inode, callback); 16075571f1e6SDan Schatzberg 16085571f1e6SDan Schatzberg err = -ECHILD; 16095571f1e6SDan Schatzberg if (!dentry) 16105571f1e6SDan Schatzberg goto out_err; 16115571f1e6SDan Schatzberg 16125571f1e6SDan Schatzberg page = alloc_page(GFP_KERNEL); 16135571f1e6SDan Schatzberg err = -ENOMEM; 16145571f1e6SDan Schatzberg if (!page) 16155571f1e6SDan Schatzberg goto out_err; 16165571f1e6SDan Schatzberg 16175571f1e6SDan Schatzberg err = fuse_readlink_page(inode, page); 16185571f1e6SDan Schatzberg if (err) { 16195571f1e6SDan Schatzberg __free_page(page); 16205571f1e6SDan Schatzberg goto out_err; 16215571f1e6SDan Schatzberg } 16225571f1e6SDan Schatzberg 16235571f1e6SDan Schatzberg set_delayed_call(callback, page_put_link, page); 16245571f1e6SDan Schatzberg 16255571f1e6SDan Schatzberg return page_address(page); 16265571f1e6SDan Schatzberg 16275571f1e6SDan Schatzberg out_err: 16285571f1e6SDan Schatzberg return ERR_PTR(err); 1629e5e5558eSMiklos Szeredi } 1630e5e5558eSMiklos Szeredi 1631e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file) 1632e5e5558eSMiklos Szeredi { 163391fe96b4SMiklos Szeredi return fuse_open_common(inode, file, true); 1634e5e5558eSMiklos Szeredi } 1635e5e5558eSMiklos Szeredi 1636e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file) 1637e5e5558eSMiklos Szeredi { 16382e64ff15SChad Austin fuse_release_common(file, true); 16398b0797a4SMiklos Szeredi 16408b0797a4SMiklos Szeredi return 0; 1641e5e5558eSMiklos Szeredi } 1642e5e5558eSMiklos Szeredi 164302c24a82SJosef Bacik static int fuse_dir_fsync(struct file *file, loff_t start, loff_t end, 164402c24a82SJosef Bacik int datasync) 164582547981SMiklos Szeredi { 1646a9c2d1e8SMiklos Szeredi struct inode *inode = file->f_mapping->host; 1647a9c2d1e8SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1648a9c2d1e8SMiklos Szeredi int err; 1649a9c2d1e8SMiklos Szeredi 16505d069dbeSMiklos Szeredi if (fuse_is_bad(inode)) 1651a9c2d1e8SMiklos Szeredi return -EIO; 1652a9c2d1e8SMiklos Szeredi 1653a9c2d1e8SMiklos Szeredi if (fc->no_fsyncdir) 1654a9c2d1e8SMiklos Szeredi return 0; 1655a9c2d1e8SMiklos Szeredi 1656a9c2d1e8SMiklos Szeredi inode_lock(inode); 1657a9c2d1e8SMiklos Szeredi err = fuse_fsync_common(file, start, end, datasync, FUSE_FSYNCDIR); 1658a9c2d1e8SMiklos Szeredi if (err == -ENOSYS) { 1659a9c2d1e8SMiklos Szeredi fc->no_fsyncdir = 1; 1660a9c2d1e8SMiklos Szeredi err = 0; 1661a9c2d1e8SMiklos Szeredi } 1662a9c2d1e8SMiklos Szeredi inode_unlock(inode); 1663a9c2d1e8SMiklos Szeredi 1664a9c2d1e8SMiklos Szeredi return err; 166582547981SMiklos Szeredi } 166682547981SMiklos Szeredi 1667b18da0c5SMiklos Szeredi static long fuse_dir_ioctl(struct file *file, unsigned int cmd, 1668b18da0c5SMiklos Szeredi unsigned long arg) 1669b18da0c5SMiklos Szeredi { 1670b18da0c5SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(file->f_mapping->host); 1671b18da0c5SMiklos Szeredi 1672b18da0c5SMiklos Szeredi /* FUSE_IOCTL_DIR only supported for API version >= 7.18 */ 1673b18da0c5SMiklos Szeredi if (fc->minor < 18) 1674b18da0c5SMiklos Szeredi return -ENOTTY; 1675b18da0c5SMiklos Szeredi 1676b18da0c5SMiklos Szeredi return fuse_ioctl_common(file, cmd, arg, FUSE_IOCTL_DIR); 1677b18da0c5SMiklos Szeredi } 1678b18da0c5SMiklos Szeredi 1679b18da0c5SMiklos Szeredi static long fuse_dir_compat_ioctl(struct file *file, unsigned int cmd, 1680b18da0c5SMiklos Szeredi unsigned long arg) 1681b18da0c5SMiklos Szeredi { 1682b18da0c5SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(file->f_mapping->host); 1683b18da0c5SMiklos Szeredi 1684b18da0c5SMiklos Szeredi if (fc->minor < 18) 1685b18da0c5SMiklos Szeredi return -ENOTTY; 1686b18da0c5SMiklos Szeredi 1687b18da0c5SMiklos Szeredi return fuse_ioctl_common(file, cmd, arg, 1688b18da0c5SMiklos Szeredi FUSE_IOCTL_COMPAT | FUSE_IOCTL_DIR); 1689b18da0c5SMiklos Szeredi } 1690b18da0c5SMiklos Szeredi 1691b0aa7606SMaxim Patlasov static bool update_mtime(unsigned ivalid, bool trust_local_mtime) 169217637cbaSMiklos Szeredi { 169317637cbaSMiklos Szeredi /* Always update if mtime is explicitly set */ 169417637cbaSMiklos Szeredi if (ivalid & ATTR_MTIME_SET) 169517637cbaSMiklos Szeredi return true; 169617637cbaSMiklos Szeredi 1697b0aa7606SMaxim Patlasov /* Or if kernel i_mtime is the official one */ 1698b0aa7606SMaxim Patlasov if (trust_local_mtime) 1699b0aa7606SMaxim Patlasov return true; 1700b0aa7606SMaxim Patlasov 170117637cbaSMiklos Szeredi /* If it's an open(O_TRUNC) or an ftruncate(), don't update */ 170217637cbaSMiklos Szeredi if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE))) 170317637cbaSMiklos Szeredi return false; 170417637cbaSMiklos Szeredi 170517637cbaSMiklos Szeredi /* In all other cases update */ 170617637cbaSMiklos Szeredi return true; 170717637cbaSMiklos Szeredi } 170817637cbaSMiklos Szeredi 17098cb08329SEric W. Biederman static void iattr_to_fattr(struct fuse_conn *fc, struct iattr *iattr, 17108cb08329SEric W. Biederman struct fuse_setattr_in *arg, bool trust_local_cmtime) 17119e6268dbSMiklos Szeredi { 17129e6268dbSMiklos Szeredi unsigned ivalid = iattr->ia_valid; 17139e6268dbSMiklos Szeredi 17149e6268dbSMiklos Szeredi if (ivalid & ATTR_MODE) 1715befc649cSMiklos Szeredi arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode; 17169e6268dbSMiklos Szeredi if (ivalid & ATTR_UID) 17178cb08329SEric W. Biederman arg->valid |= FATTR_UID, arg->uid = from_kuid(fc->user_ns, iattr->ia_uid); 17189e6268dbSMiklos Szeredi if (ivalid & ATTR_GID) 17198cb08329SEric W. Biederman arg->valid |= FATTR_GID, arg->gid = from_kgid(fc->user_ns, iattr->ia_gid); 17209e6268dbSMiklos Szeredi if (ivalid & ATTR_SIZE) 1721befc649cSMiklos Szeredi arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size; 172217637cbaSMiklos Szeredi if (ivalid & ATTR_ATIME) { 172317637cbaSMiklos Szeredi arg->valid |= FATTR_ATIME; 1724befc649cSMiklos Szeredi arg->atime = iattr->ia_atime.tv_sec; 172517637cbaSMiklos Szeredi arg->atimensec = iattr->ia_atime.tv_nsec; 172617637cbaSMiklos Szeredi if (!(ivalid & ATTR_ATIME_SET)) 172717637cbaSMiklos Szeredi arg->valid |= FATTR_ATIME_NOW; 172817637cbaSMiklos Szeredi } 17293ad22c62SMaxim Patlasov if ((ivalid & ATTR_MTIME) && update_mtime(ivalid, trust_local_cmtime)) { 173017637cbaSMiklos Szeredi arg->valid |= FATTR_MTIME; 1731befc649cSMiklos Szeredi arg->mtime = iattr->ia_mtime.tv_sec; 173217637cbaSMiklos Szeredi arg->mtimensec = iattr->ia_mtime.tv_nsec; 17333ad22c62SMaxim Patlasov if (!(ivalid & ATTR_MTIME_SET) && !trust_local_cmtime) 173417637cbaSMiklos Szeredi arg->valid |= FATTR_MTIME_NOW; 17359e6268dbSMiklos Szeredi } 17363ad22c62SMaxim Patlasov if ((ivalid & ATTR_CTIME) && trust_local_cmtime) { 17373ad22c62SMaxim Patlasov arg->valid |= FATTR_CTIME; 17383ad22c62SMaxim Patlasov arg->ctime = iattr->ia_ctime.tv_sec; 17393ad22c62SMaxim Patlasov arg->ctimensec = iattr->ia_ctime.tv_nsec; 17403ad22c62SMaxim Patlasov } 17419e6268dbSMiklos Szeredi } 17429e6268dbSMiklos Szeredi 17436f9f1180SMiklos Szeredi /* 17443be5a52bSMiklos Szeredi * Prevent concurrent writepages on inode 17453be5a52bSMiklos Szeredi * 17463be5a52bSMiklos Szeredi * This is done by adding a negative bias to the inode write counter 17473be5a52bSMiklos Szeredi * and waiting for all pending writes to finish. 17483be5a52bSMiklos Szeredi */ 17493be5a52bSMiklos Szeredi void fuse_set_nowrite(struct inode *inode) 17503be5a52bSMiklos Szeredi { 17513be5a52bSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 17523be5a52bSMiklos Szeredi 17535955102cSAl Viro BUG_ON(!inode_is_locked(inode)); 17543be5a52bSMiklos Szeredi 1755f15ecfefSKirill Tkhai spin_lock(&fi->lock); 17563be5a52bSMiklos Szeredi BUG_ON(fi->writectr < 0); 17573be5a52bSMiklos Szeredi fi->writectr += FUSE_NOWRITE; 1758f15ecfefSKirill Tkhai spin_unlock(&fi->lock); 17593be5a52bSMiklos Szeredi wait_event(fi->page_waitq, fi->writectr == FUSE_NOWRITE); 17603be5a52bSMiklos Szeredi } 17613be5a52bSMiklos Szeredi 17623be5a52bSMiklos Szeredi /* 17633be5a52bSMiklos Szeredi * Allow writepages on inode 17643be5a52bSMiklos Szeredi * 17653be5a52bSMiklos Szeredi * Remove the bias from the writecounter and send any queued 17663be5a52bSMiklos Szeredi * writepages. 17673be5a52bSMiklos Szeredi */ 17683be5a52bSMiklos Szeredi static void __fuse_release_nowrite(struct inode *inode) 17693be5a52bSMiklos Szeredi { 17703be5a52bSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 17713be5a52bSMiklos Szeredi 17723be5a52bSMiklos Szeredi BUG_ON(fi->writectr != FUSE_NOWRITE); 17733be5a52bSMiklos Szeredi fi->writectr = 0; 17743be5a52bSMiklos Szeredi fuse_flush_writepages(inode); 17753be5a52bSMiklos Szeredi } 17763be5a52bSMiklos Szeredi 17773be5a52bSMiklos Szeredi void fuse_release_nowrite(struct inode *inode) 17783be5a52bSMiklos Szeredi { 1779f15ecfefSKirill Tkhai struct fuse_inode *fi = get_fuse_inode(inode); 17803be5a52bSMiklos Szeredi 1781f15ecfefSKirill Tkhai spin_lock(&fi->lock); 17823be5a52bSMiklos Szeredi __fuse_release_nowrite(inode); 1783f15ecfefSKirill Tkhai spin_unlock(&fi->lock); 17843be5a52bSMiklos Szeredi } 17853be5a52bSMiklos Szeredi 17867078187aSMiklos Szeredi static void fuse_setattr_fill(struct fuse_conn *fc, struct fuse_args *args, 1787b0aa7606SMaxim Patlasov struct inode *inode, 1788b0aa7606SMaxim Patlasov struct fuse_setattr_in *inarg_p, 1789b0aa7606SMaxim Patlasov struct fuse_attr_out *outarg_p) 1790b0aa7606SMaxim Patlasov { 1791d5b48543SMiklos Szeredi args->opcode = FUSE_SETATTR; 1792d5b48543SMiklos Szeredi args->nodeid = get_node_id(inode); 1793d5b48543SMiklos Szeredi args->in_numargs = 1; 1794d5b48543SMiklos Szeredi args->in_args[0].size = sizeof(*inarg_p); 1795d5b48543SMiklos Szeredi args->in_args[0].value = inarg_p; 1796d5b48543SMiklos Szeredi args->out_numargs = 1; 1797d5b48543SMiklos Szeredi args->out_args[0].size = sizeof(*outarg_p); 1798d5b48543SMiklos Szeredi args->out_args[0].value = outarg_p; 1799b0aa7606SMaxim Patlasov } 1800b0aa7606SMaxim Patlasov 1801b0aa7606SMaxim Patlasov /* 1802b0aa7606SMaxim Patlasov * Flush inode->i_mtime to the server 1803b0aa7606SMaxim Patlasov */ 1804ab9e13f7SMaxim Patlasov int fuse_flush_times(struct inode *inode, struct fuse_file *ff) 1805b0aa7606SMaxim Patlasov { 1806fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(inode); 18077078187aSMiklos Szeredi FUSE_ARGS(args); 1808b0aa7606SMaxim Patlasov struct fuse_setattr_in inarg; 1809b0aa7606SMaxim Patlasov struct fuse_attr_out outarg; 1810b0aa7606SMaxim Patlasov 1811b0aa7606SMaxim Patlasov memset(&inarg, 0, sizeof(inarg)); 1812b0aa7606SMaxim Patlasov memset(&outarg, 0, sizeof(outarg)); 1813b0aa7606SMaxim Patlasov 1814ab9e13f7SMaxim Patlasov inarg.valid = FATTR_MTIME; 1815b0aa7606SMaxim Patlasov inarg.mtime = inode->i_mtime.tv_sec; 1816b0aa7606SMaxim Patlasov inarg.mtimensec = inode->i_mtime.tv_nsec; 1817fcee216bSMax Reitz if (fm->fc->minor >= 23) { 1818ab9e13f7SMaxim Patlasov inarg.valid |= FATTR_CTIME; 1819ceb2d5e9SJeff Layton inarg.ctime = inode_get_ctime(inode).tv_sec; 1820ceb2d5e9SJeff Layton inarg.ctimensec = inode_get_ctime(inode).tv_nsec; 1821ab9e13f7SMaxim Patlasov } 18221e18bda8SMiklos Szeredi if (ff) { 18231e18bda8SMiklos Szeredi inarg.valid |= FATTR_FH; 18241e18bda8SMiklos Szeredi inarg.fh = ff->fh; 18251e18bda8SMiklos Szeredi } 1826fcee216bSMax Reitz fuse_setattr_fill(fm->fc, &args, inode, &inarg, &outarg); 1827b0aa7606SMaxim Patlasov 1828fcee216bSMax Reitz return fuse_simple_request(fm, &args); 1829b0aa7606SMaxim Patlasov } 1830b0aa7606SMaxim Patlasov 18313be5a52bSMiklos Szeredi /* 18326f9f1180SMiklos Szeredi * Set attributes, and at the same time refresh them. 18336f9f1180SMiklos Szeredi * 18346f9f1180SMiklos Szeredi * Truncation is slightly complicated, because the 'truncate' request 18356f9f1180SMiklos Szeredi * may fail, in which case we don't want to touch the mapping. 18369ffbb916SMiklos Szeredi * vmtruncate() doesn't allow for this case, so do the rlimit checking 18379ffbb916SMiklos Szeredi * and the actual truncation by hand. 18386f9f1180SMiklos Szeredi */ 183962490330SJan Kara int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, 184049d4914fSMiklos Szeredi struct file *file) 18419e6268dbSMiklos Szeredi { 184262490330SJan Kara struct inode *inode = d_inode(dentry); 1843fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(inode); 1844fcee216bSMax Reitz struct fuse_conn *fc = fm->fc; 184506a7c3c2SMaxim Patlasov struct fuse_inode *fi = get_fuse_inode(inode); 18468bcbbe9cSJan Kara struct address_space *mapping = inode->i_mapping; 18477078187aSMiklos Szeredi FUSE_ARGS(args); 18489e6268dbSMiklos Szeredi struct fuse_setattr_in inarg; 18499e6268dbSMiklos Szeredi struct fuse_attr_out outarg; 18503be5a52bSMiklos Szeredi bool is_truncate = false; 1851c15016b7SMiklos Szeredi bool is_wb = fc->writeback_cache && S_ISREG(inode->i_mode); 18523be5a52bSMiklos Szeredi loff_t oldsize; 18539e6268dbSMiklos Szeredi int err; 1854c15016b7SMiklos Szeredi bool trust_local_cmtime = is_wb; 18556ae330caSVivek Goyal bool fault_blocked = false; 18569e6268dbSMiklos Szeredi 185729433a29SMiklos Szeredi if (!fc->default_permissions) 1858db78b877SChristoph Hellwig attr->ia_valid |= ATTR_FORCE; 1859db78b877SChristoph Hellwig 1860c1632a0fSChristian Brauner err = setattr_prepare(&nop_mnt_idmap, dentry, attr); 18611e9a4ed9SMiklos Szeredi if (err) 18621e9a4ed9SMiklos Szeredi return err; 18631e9a4ed9SMiklos Szeredi 18646ae330caSVivek Goyal if (attr->ia_valid & ATTR_SIZE) { 18656ae330caSVivek Goyal if (WARN_ON(!S_ISREG(inode->i_mode))) 18666ae330caSVivek Goyal return -EIO; 18676ae330caSVivek Goyal is_truncate = true; 18686ae330caSVivek Goyal } 18696ae330caSVivek Goyal 18706ae330caSVivek Goyal if (FUSE_IS_DAX(inode) && is_truncate) { 18718bcbbe9cSJan Kara filemap_invalidate_lock(mapping); 18726ae330caSVivek Goyal fault_blocked = true; 18736ae330caSVivek Goyal err = fuse_dax_break_layouts(inode, 0, 0); 18746ae330caSVivek Goyal if (err) { 18758bcbbe9cSJan Kara filemap_invalidate_unlock(mapping); 18766ae330caSVivek Goyal return err; 18776ae330caSVivek Goyal } 18786ae330caSVivek Goyal } 18796ae330caSVivek Goyal 18808d56adddSMiklos Szeredi if (attr->ia_valid & ATTR_OPEN) { 1881df0e91d4SMiklos Szeredi /* This is coming from open(..., ... | O_TRUNC); */ 1882df0e91d4SMiklos Szeredi WARN_ON(!(attr->ia_valid & ATTR_SIZE)); 1883df0e91d4SMiklos Szeredi WARN_ON(attr->ia_size != 0); 1884df0e91d4SMiklos Szeredi if (fc->atomic_o_trunc) { 1885df0e91d4SMiklos Szeredi /* 1886df0e91d4SMiklos Szeredi * No need to send request to userspace, since actual 1887df0e91d4SMiklos Szeredi * truncation has already been done by OPEN. But still 1888df0e91d4SMiklos Szeredi * need to truncate page cache. 1889df0e91d4SMiklos Szeredi */ 1890df0e91d4SMiklos Szeredi i_size_write(inode, 0); 1891df0e91d4SMiklos Szeredi truncate_pagecache(inode, 0); 18926ae330caSVivek Goyal goto out; 1893df0e91d4SMiklos Szeredi } 18948d56adddSMiklos Szeredi file = NULL; 18958d56adddSMiklos Szeredi } 18966ff958edSMiklos Szeredi 1897b24e7598SMiklos Szeredi /* Flush dirty data/metadata before non-truncate SETATTR */ 1898c15016b7SMiklos Szeredi if (is_wb && 1899b24e7598SMiklos Szeredi attr->ia_valid & 1900b24e7598SMiklos Szeredi (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_MTIME_SET | 1901b24e7598SMiklos Szeredi ATTR_TIMES_SET)) { 1902b24e7598SMiklos Szeredi err = write_inode_now(inode, true); 1903b24e7598SMiklos Szeredi if (err) 1904b24e7598SMiklos Szeredi return err; 1905b24e7598SMiklos Szeredi 1906b24e7598SMiklos Szeredi fuse_set_nowrite(inode); 1907b24e7598SMiklos Szeredi fuse_release_nowrite(inode); 1908b24e7598SMiklos Szeredi } 1909b24e7598SMiklos Szeredi 191006a7c3c2SMaxim Patlasov if (is_truncate) { 19113be5a52bSMiklos Szeredi fuse_set_nowrite(inode); 191206a7c3c2SMaxim Patlasov set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); 19133ad22c62SMaxim Patlasov if (trust_local_cmtime && attr->ia_size != inode->i_size) 19143ad22c62SMaxim Patlasov attr->ia_valid |= ATTR_MTIME | ATTR_CTIME; 191506a7c3c2SMaxim Patlasov } 19163be5a52bSMiklos Szeredi 19179e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 19180e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 19198cb08329SEric W. Biederman iattr_to_fattr(fc, attr, &inarg, trust_local_cmtime); 192049d4914fSMiklos Szeredi if (file) { 192149d4914fSMiklos Szeredi struct fuse_file *ff = file->private_data; 192249d4914fSMiklos Szeredi inarg.valid |= FATTR_FH; 192349d4914fSMiklos Szeredi inarg.fh = ff->fh; 192449d4914fSMiklos Szeredi } 192531792161SVivek Goyal 192631792161SVivek Goyal /* Kill suid/sgid for non-directory chown unconditionally */ 192731792161SVivek Goyal if (fc->handle_killpriv_v2 && !S_ISDIR(inode->i_mode) && 192831792161SVivek Goyal attr->ia_valid & (ATTR_UID | ATTR_GID)) 192931792161SVivek Goyal inarg.valid |= FATTR_KILL_SUIDGID; 193031792161SVivek Goyal 1931f3332114SMiklos Szeredi if (attr->ia_valid & ATTR_SIZE) { 1932f3332114SMiklos Szeredi /* For mandatory locking in truncate */ 1933f3332114SMiklos Szeredi inarg.valid |= FATTR_LOCKOWNER; 1934f3332114SMiklos Szeredi inarg.lock_owner = fuse_lock_owner_id(fc, current->files); 193531792161SVivek Goyal 193631792161SVivek Goyal /* Kill suid/sgid for truncate only if no CAP_FSETID */ 193731792161SVivek Goyal if (fc->handle_killpriv_v2 && !capable(CAP_FSETID)) 193831792161SVivek Goyal inarg.valid |= FATTR_KILL_SUIDGID; 1939f3332114SMiklos Szeredi } 19407078187aSMiklos Szeredi fuse_setattr_fill(fc, &args, inode, &inarg, &outarg); 1941fcee216bSMax Reitz err = fuse_simple_request(fm, &args); 1942e00d2c2dSMiklos Szeredi if (err) { 1943e00d2c2dSMiklos Szeredi if (err == -EINTR) 1944e00d2c2dSMiklos Szeredi fuse_invalidate_attr(inode); 19453be5a52bSMiklos Szeredi goto error; 1946e00d2c2dSMiklos Szeredi } 1947e00d2c2dSMiklos Szeredi 1948eb59bd17SMiklos Szeredi if (fuse_invalid_attr(&outarg.attr) || 19496e3e2c43SAl Viro inode_wrong_type(inode, outarg.attr.mode)) { 19505d069dbeSMiklos Szeredi fuse_make_bad(inode); 19513be5a52bSMiklos Szeredi err = -EIO; 19523be5a52bSMiklos Szeredi goto error; 19539e6268dbSMiklos Szeredi } 19549e6268dbSMiklos Szeredi 1955f15ecfefSKirill Tkhai spin_lock(&fi->lock); 1956b0aa7606SMaxim Patlasov /* the kernel maintains i_mtime locally */ 19573ad22c62SMaxim Patlasov if (trust_local_cmtime) { 19583ad22c62SMaxim Patlasov if (attr->ia_valid & ATTR_MTIME) 1959b0aa7606SMaxim Patlasov inode->i_mtime = attr->ia_mtime; 19603ad22c62SMaxim Patlasov if (attr->ia_valid & ATTR_CTIME) 1961ceb2d5e9SJeff Layton inode_set_ctime_to_ts(inode, attr->ia_ctime); 19621e18bda8SMiklos Szeredi /* FIXME: clear I_DIRTY_SYNC? */ 1963b0aa7606SMaxim Patlasov } 1964b0aa7606SMaxim Patlasov 1965972f4c46SMiklos Szeredi fuse_change_attributes_common(inode, &outarg.attr, NULL, 19669dc10a54SMiklos Szeredi ATTR_TIMEOUT(&outarg), 19674b52f059SMiklos Szeredi fuse_get_cache_mask(inode)); 19683be5a52bSMiklos Szeredi oldsize = inode->i_size; 19698373200bSPavel Emelyanov /* see the comment in fuse_change_attributes() */ 1970c15016b7SMiklos Szeredi if (!is_wb || is_truncate) 19713be5a52bSMiklos Szeredi i_size_write(inode, outarg.attr.size); 19723be5a52bSMiklos Szeredi 19733be5a52bSMiklos Szeredi if (is_truncate) { 1974f15ecfefSKirill Tkhai /* NOTE: this may release/reacquire fi->lock */ 19753be5a52bSMiklos Szeredi __fuse_release_nowrite(inode); 19763be5a52bSMiklos Szeredi } 1977f15ecfefSKirill Tkhai spin_unlock(&fi->lock); 19783be5a52bSMiklos Szeredi 19793be5a52bSMiklos Szeredi /* 19803be5a52bSMiklos Szeredi * Only call invalidate_inode_pages2() after removing 19812bf06b8eSMatthew Wilcox (Oracle) * FUSE_NOWRITE, otherwise fuse_launder_folio() would deadlock. 19823be5a52bSMiklos Szeredi */ 19838373200bSPavel Emelyanov if ((is_truncate || !is_wb) && 19848373200bSPavel Emelyanov S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) { 19857caef267SKirill A. Shutemov truncate_pagecache(inode, outarg.attr.size); 19868bcbbe9cSJan Kara invalidate_inode_pages2(mapping); 19873be5a52bSMiklos Szeredi } 19883be5a52bSMiklos Szeredi 198906a7c3c2SMaxim Patlasov clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); 19906ae330caSVivek Goyal out: 19916ae330caSVivek Goyal if (fault_blocked) 19928bcbbe9cSJan Kara filemap_invalidate_unlock(mapping); 19936ae330caSVivek Goyal 1994e00d2c2dSMiklos Szeredi return 0; 19953be5a52bSMiklos Szeredi 19963be5a52bSMiklos Szeredi error: 19973be5a52bSMiklos Szeredi if (is_truncate) 19983be5a52bSMiklos Szeredi fuse_release_nowrite(inode); 19993be5a52bSMiklos Szeredi 200006a7c3c2SMaxim Patlasov clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); 20016ae330caSVivek Goyal 20026ae330caSVivek Goyal if (fault_blocked) 20038bcbbe9cSJan Kara filemap_invalidate_unlock(mapping); 20043be5a52bSMiklos Szeredi return err; 20059e6268dbSMiklos Szeredi } 20069e6268dbSMiklos Szeredi 2007c1632a0fSChristian Brauner static int fuse_setattr(struct mnt_idmap *idmap, struct dentry *entry, 2008549c7297SChristian Brauner struct iattr *attr) 200949d4914fSMiklos Szeredi { 20102b0143b5SDavid Howells struct inode *inode = d_inode(entry); 20115e940c1dSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 2012a09f99edSMiklos Szeredi struct file *file = (attr->ia_valid & ATTR_FILE) ? attr->ia_file : NULL; 20135e2b8828SMiklos Szeredi int ret; 2014efb9fa9eSMaxim Patlasov 20155d069dbeSMiklos Szeredi if (fuse_is_bad(inode)) 20165d069dbeSMiklos Szeredi return -EIO; 20175d069dbeSMiklos Szeredi 2018efb9fa9eSMaxim Patlasov if (!fuse_allow_current_process(get_fuse_conn(inode))) 2019efb9fa9eSMaxim Patlasov return -EACCES; 2020efb9fa9eSMaxim Patlasov 2021a09f99edSMiklos Szeredi if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) { 2022a09f99edSMiklos Szeredi attr->ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | 2023a09f99edSMiklos Szeredi ATTR_MODE); 20245e940c1dSMiklos Szeredi 2025a09f99edSMiklos Szeredi /* 20265e940c1dSMiklos Szeredi * The only sane way to reliably kill suid/sgid is to do it in 20275e940c1dSMiklos Szeredi * the userspace filesystem 20285e940c1dSMiklos Szeredi * 20295e940c1dSMiklos Szeredi * This should be done on write(), truncate() and chown(). 20305e940c1dSMiklos Szeredi */ 20318981bdfdSVivek Goyal if (!fc->handle_killpriv && !fc->handle_killpriv_v2) { 20325e940c1dSMiklos Szeredi /* 20335e940c1dSMiklos Szeredi * ia_mode calculation may have used stale i_mode. 20345e940c1dSMiklos Szeredi * Refresh and recalculate. 2035a09f99edSMiklos Szeredi */ 2036a09f99edSMiklos Szeredi ret = fuse_do_getattr(inode, NULL, file); 2037a09f99edSMiklos Szeredi if (ret) 2038a09f99edSMiklos Szeredi return ret; 2039a09f99edSMiklos Szeredi 2040a09f99edSMiklos Szeredi attr->ia_mode = inode->i_mode; 2041c01638f5SMiklos Szeredi if (inode->i_mode & S_ISUID) { 2042a09f99edSMiklos Szeredi attr->ia_valid |= ATTR_MODE; 2043a09f99edSMiklos Szeredi attr->ia_mode &= ~S_ISUID; 2044a09f99edSMiklos Szeredi } 2045c01638f5SMiklos Szeredi if ((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { 2046a09f99edSMiklos Szeredi attr->ia_valid |= ATTR_MODE; 2047a09f99edSMiklos Szeredi attr->ia_mode &= ~S_ISGID; 2048a09f99edSMiklos Szeredi } 2049a09f99edSMiklos Szeredi } 20505e940c1dSMiklos Szeredi } 2051a09f99edSMiklos Szeredi if (!attr->ia_valid) 2052a09f99edSMiklos Szeredi return 0; 2053a09f99edSMiklos Szeredi 2054abb5a14fSLinus Torvalds ret = fuse_do_setattr(entry, attr, file); 20555e2b8828SMiklos Szeredi if (!ret) { 205660bcc88aSSeth Forshee /* 205760bcc88aSSeth Forshee * If filesystem supports acls it may have updated acl xattrs in 205860bcc88aSSeth Forshee * the filesystem, so forget cached acls for the inode. 205960bcc88aSSeth Forshee */ 206060bcc88aSSeth Forshee if (fc->posix_acl) 206160bcc88aSSeth Forshee forget_all_cached_acls(inode); 206260bcc88aSSeth Forshee 20635e2b8828SMiklos Szeredi /* Directory mode changed, may need to revalidate access */ 20645e2b8828SMiklos Szeredi if (d_is_dir(entry) && (attr->ia_valid & ATTR_MODE)) 20655e2b8828SMiklos Szeredi fuse_invalidate_entry_cache(entry); 20665e2b8828SMiklos Szeredi } 20675e2b8828SMiklos Szeredi return ret; 206849d4914fSMiklos Szeredi } 206949d4914fSMiklos Szeredi 2070b74d24f7SChristian Brauner static int fuse_getattr(struct mnt_idmap *idmap, 2071549c7297SChristian Brauner const struct path *path, struct kstat *stat, 2072a528d35eSDavid Howells u32 request_mask, unsigned int flags) 2073e5e5558eSMiklos Szeredi { 2074a528d35eSDavid Howells struct inode *inode = d_inode(path->dentry); 2075244f6385SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 2076244f6385SMiklos Szeredi 20775d069dbeSMiklos Szeredi if (fuse_is_bad(inode)) 20785d069dbeSMiklos Szeredi return -EIO; 20795d069dbeSMiklos Szeredi 20805157da2cSMiklos Szeredi if (!fuse_allow_current_process(fc)) { 20815157da2cSMiklos Szeredi if (!request_mask) { 20825157da2cSMiklos Szeredi /* 20835157da2cSMiklos Szeredi * If user explicitly requested *nothing* then don't 20845157da2cSMiklos Szeredi * error out, but return st_dev only. 20855157da2cSMiklos Szeredi */ 20865157da2cSMiklos Szeredi stat->result_mask = 0; 20875157da2cSMiklos Szeredi stat->dev = inode->i_sb->s_dev; 20885157da2cSMiklos Szeredi return 0; 20895157da2cSMiklos Szeredi } 2090244f6385SMiklos Szeredi return -EACCES; 20915157da2cSMiklos Szeredi } 2092244f6385SMiklos Szeredi 20932f1e8196SMiklos Szeredi return fuse_update_get_attr(inode, NULL, stat, request_mask, flags); 2094e5e5558eSMiklos Szeredi } 2095e5e5558eSMiklos Szeredi 2096754661f1SArjan van de Ven static const struct inode_operations fuse_dir_inode_operations = { 2097e5e5558eSMiklos Szeredi .lookup = fuse_lookup, 20989e6268dbSMiklos Szeredi .mkdir = fuse_mkdir, 20999e6268dbSMiklos Szeredi .symlink = fuse_symlink, 21009e6268dbSMiklos Szeredi .unlink = fuse_unlink, 21019e6268dbSMiklos Szeredi .rmdir = fuse_rmdir, 21022773bf00SMiklos Szeredi .rename = fuse_rename2, 21039e6268dbSMiklos Szeredi .link = fuse_link, 21049e6268dbSMiklos Szeredi .setattr = fuse_setattr, 21059e6268dbSMiklos Szeredi .create = fuse_create, 2106c8ccbe03SMiklos Szeredi .atomic_open = fuse_atomic_open, 21077d375390SMiklos Szeredi .tmpfile = fuse_tmpfile, 21089e6268dbSMiklos Szeredi .mknod = fuse_mknod, 2109e5e5558eSMiklos Szeredi .permission = fuse_permission, 2110e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 211192a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 2112facd6105SChristian Brauner .get_inode_acl = fuse_get_inode_acl, 2113facd6105SChristian Brauner .get_acl = fuse_get_acl, 211460bcc88aSSeth Forshee .set_acl = fuse_set_acl, 211572227eacSMiklos Szeredi .fileattr_get = fuse_fileattr_get, 211672227eacSMiklos Szeredi .fileattr_set = fuse_fileattr_set, 2117e5e5558eSMiklos Szeredi }; 2118e5e5558eSMiklos Szeredi 21194b6f5d20SArjan van de Ven static const struct file_operations fuse_dir_operations = { 2120b6aeadedSMiklos Szeredi .llseek = generic_file_llseek, 2121e5e5558eSMiklos Szeredi .read = generic_read_dir, 2122d9b3dbdcSAl Viro .iterate_shared = fuse_readdir, 2123e5e5558eSMiklos Szeredi .open = fuse_dir_open, 2124e5e5558eSMiklos Szeredi .release = fuse_dir_release, 212582547981SMiklos Szeredi .fsync = fuse_dir_fsync, 2126b18da0c5SMiklos Szeredi .unlocked_ioctl = fuse_dir_ioctl, 2127b18da0c5SMiklos Szeredi .compat_ioctl = fuse_dir_compat_ioctl, 2128e5e5558eSMiklos Szeredi }; 2129e5e5558eSMiklos Szeredi 2130754661f1SArjan van de Ven static const struct inode_operations fuse_common_inode_operations = { 21319e6268dbSMiklos Szeredi .setattr = fuse_setattr, 2132e5e5558eSMiklos Szeredi .permission = fuse_permission, 2133e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 213492a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 2135facd6105SChristian Brauner .get_inode_acl = fuse_get_inode_acl, 2136facd6105SChristian Brauner .get_acl = fuse_get_acl, 213760bcc88aSSeth Forshee .set_acl = fuse_set_acl, 213872227eacSMiklos Szeredi .fileattr_get = fuse_fileattr_get, 213972227eacSMiklos Szeredi .fileattr_set = fuse_fileattr_set, 2140e5e5558eSMiklos Szeredi }; 2141e5e5558eSMiklos Szeredi 2142754661f1SArjan van de Ven static const struct inode_operations fuse_symlink_inode_operations = { 21439e6268dbSMiklos Szeredi .setattr = fuse_setattr, 21446b255391SAl Viro .get_link = fuse_get_link, 2145e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 214692a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 2147e5e5558eSMiklos Szeredi }; 2148e5e5558eSMiklos Szeredi 2149e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode) 2150e5e5558eSMiklos Szeredi { 2151e5e5558eSMiklos Szeredi inode->i_op = &fuse_common_inode_operations; 2152e5e5558eSMiklos Szeredi } 2153e5e5558eSMiklos Szeredi 2154e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode) 2155e5e5558eSMiklos Szeredi { 2156ab2257e9SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 2157ab2257e9SMiklos Szeredi 2158e5e5558eSMiklos Szeredi inode->i_op = &fuse_dir_inode_operations; 2159e5e5558eSMiklos Szeredi inode->i_fop = &fuse_dir_operations; 2160ab2257e9SMiklos Szeredi 2161ab2257e9SMiklos Szeredi spin_lock_init(&fi->rdc.lock); 2162ab2257e9SMiklos Szeredi fi->rdc.cached = false; 2163ab2257e9SMiklos Szeredi fi->rdc.size = 0; 2164ab2257e9SMiklos Szeredi fi->rdc.pos = 0; 2165ab2257e9SMiklos Szeredi fi->rdc.version = 0; 2166e5e5558eSMiklos Szeredi } 2167e5e5558eSMiklos Szeredi 21685efd00e4SMatthew Wilcox (Oracle) static int fuse_symlink_read_folio(struct file *null, struct folio *folio) 21695571f1e6SDan Schatzberg { 21705efd00e4SMatthew Wilcox (Oracle) int err = fuse_readlink_page(folio->mapping->host, &folio->page); 21715571f1e6SDan Schatzberg 21725571f1e6SDan Schatzberg if (!err) 21735efd00e4SMatthew Wilcox (Oracle) folio_mark_uptodate(folio); 21745571f1e6SDan Schatzberg 21755efd00e4SMatthew Wilcox (Oracle) folio_unlock(folio); 21765571f1e6SDan Schatzberg 21775571f1e6SDan Schatzberg return err; 21785571f1e6SDan Schatzberg } 21795571f1e6SDan Schatzberg 21805571f1e6SDan Schatzberg static const struct address_space_operations fuse_symlink_aops = { 21815efd00e4SMatthew Wilcox (Oracle) .read_folio = fuse_symlink_read_folio, 21825571f1e6SDan Schatzberg }; 21835571f1e6SDan Schatzberg 2184e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode) 2185e5e5558eSMiklos Szeredi { 2186e5e5558eSMiklos Szeredi inode->i_op = &fuse_symlink_inode_operations; 21875571f1e6SDan Schatzberg inode->i_data.a_ops = &fuse_symlink_aops; 21885571f1e6SDan Schatzberg inode_nohighmem(inode); 2189e5e5558eSMiklos Szeredi } 2190