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> 13e5e5558eSMiklos Szeredi #include <linux/sched.h> 14e5e5558eSMiklos Szeredi #include <linux/namei.h> 1507e77dcaSMiklos Szeredi #include <linux/slab.h> 16703c7362SSeth Forshee #include <linux/xattr.h> 1760bcc88aSSeth Forshee #include <linux/posix_acl.h> 18e5e5558eSMiklos Szeredi 198d3af7f3SAl Viro static bool fuse_use_readdirplus(struct inode *dir, struct dir_context *ctx) 204582a4abSFeng Shuo { 214582a4abSFeng Shuo struct fuse_conn *fc = get_fuse_conn(dir); 224582a4abSFeng Shuo struct fuse_inode *fi = get_fuse_inode(dir); 234582a4abSFeng Shuo 244582a4abSFeng Shuo if (!fc->do_readdirplus) 254582a4abSFeng Shuo return false; 26634734b6SEric Wong if (!fc->readdirplus_auto) 27634734b6SEric Wong return true; 284582a4abSFeng Shuo if (test_and_clear_bit(FUSE_I_ADVISE_RDPLUS, &fi->state)) 294582a4abSFeng Shuo return true; 308d3af7f3SAl Viro if (ctx->pos == 0) 314582a4abSFeng Shuo return true; 324582a4abSFeng Shuo return false; 334582a4abSFeng Shuo } 344582a4abSFeng Shuo 354582a4abSFeng Shuo static void fuse_advise_use_readdirplus(struct inode *dir) 364582a4abSFeng Shuo { 374582a4abSFeng Shuo struct fuse_inode *fi = get_fuse_inode(dir); 384582a4abSFeng Shuo 394582a4abSFeng Shuo set_bit(FUSE_I_ADVISE_RDPLUS, &fi->state); 404582a4abSFeng Shuo } 414582a4abSFeng Shuo 42f75fdf22SMiklos Szeredi union fuse_dentry { 43f75fdf22SMiklos Szeredi u64 time; 44f75fdf22SMiklos Szeredi struct rcu_head rcu; 45f75fdf22SMiklos Szeredi }; 46f75fdf22SMiklos Szeredi 470a0898cfSMiklos Szeredi static inline void fuse_dentry_settime(struct dentry *entry, u64 time) 480a0898cfSMiklos Szeredi { 49f75fdf22SMiklos Szeredi ((union fuse_dentry *) entry->d_fsdata)->time = time; 500a0898cfSMiklos Szeredi } 510a0898cfSMiklos Szeredi 520a0898cfSMiklos Szeredi static inline u64 fuse_dentry_time(struct dentry *entry) 530a0898cfSMiklos Szeredi { 54f75fdf22SMiklos Szeredi return ((union fuse_dentry *) entry->d_fsdata)->time; 550a0898cfSMiklos Szeredi } 560a0898cfSMiklos Szeredi 576f9f1180SMiklos Szeredi /* 586f9f1180SMiklos Szeredi * FUSE caches dentries and attributes with separate timeout. The 596f9f1180SMiklos Szeredi * time in jiffies until the dentry/attributes are valid is stored in 60f75fdf22SMiklos Szeredi * dentry->d_fsdata and fuse_inode->i_time respectively. 616f9f1180SMiklos Szeredi */ 626f9f1180SMiklos Szeredi 636f9f1180SMiklos Szeredi /* 646f9f1180SMiklos Szeredi * Calculate the time in jiffies until a dentry/attributes are valid 656f9f1180SMiklos Szeredi */ 66bcb6f6d2SMiklos Szeredi static u64 time_to_jiffies(u64 sec, u32 nsec) 67e5e5558eSMiklos Szeredi { 68685d16ddSMiklos Szeredi if (sec || nsec) { 69bcb6f6d2SMiklos Szeredi struct timespec64 ts = { 70bcb6f6d2SMiklos Szeredi sec, 7121067527SDavid Sheets min_t(u32, nsec, NSEC_PER_SEC - 1) 72bcb6f6d2SMiklos Szeredi }; 73bcb6f6d2SMiklos Szeredi 74bcb6f6d2SMiklos Szeredi return get_jiffies_64() + timespec64_to_jiffies(&ts); 75685d16ddSMiklos Szeredi } else 760a0898cfSMiklos Szeredi return 0; 77e5e5558eSMiklos Szeredi } 78e5e5558eSMiklos Szeredi 796f9f1180SMiklos Szeredi /* 806f9f1180SMiklos Szeredi * Set dentry and possibly attribute timeouts from the lookup/mk* 816f9f1180SMiklos Szeredi * replies 826f9f1180SMiklos Szeredi */ 831fb69e78SMiklos Szeredi static void fuse_change_entry_timeout(struct dentry *entry, 841fb69e78SMiklos Szeredi struct fuse_entry_out *o) 850aa7c699SMiklos Szeredi { 860a0898cfSMiklos Szeredi fuse_dentry_settime(entry, 870a0898cfSMiklos Szeredi time_to_jiffies(o->entry_valid, o->entry_valid_nsec)); 881fb69e78SMiklos Szeredi } 891fb69e78SMiklos Szeredi 901fb69e78SMiklos Szeredi static u64 attr_timeout(struct fuse_attr_out *o) 911fb69e78SMiklos Szeredi { 921fb69e78SMiklos Szeredi return time_to_jiffies(o->attr_valid, o->attr_valid_nsec); 931fb69e78SMiklos Szeredi } 941fb69e78SMiklos Szeredi 951fb69e78SMiklos Szeredi static u64 entry_attr_timeout(struct fuse_entry_out *o) 961fb69e78SMiklos Szeredi { 971fb69e78SMiklos Szeredi return time_to_jiffies(o->attr_valid, o->attr_valid_nsec); 988cbdf1e6SMiklos Szeredi } 998cbdf1e6SMiklos Szeredi 1006f9f1180SMiklos Szeredi /* 1016f9f1180SMiklos Szeredi * Mark the attributes as stale, so that at the next call to 1026f9f1180SMiklos Szeredi * ->getattr() they will be fetched from userspace 1036f9f1180SMiklos Szeredi */ 1048cbdf1e6SMiklos Szeredi void fuse_invalidate_attr(struct inode *inode) 1058cbdf1e6SMiklos Szeredi { 1060a0898cfSMiklos Szeredi get_fuse_inode(inode)->i_time = 0; 1078cbdf1e6SMiklos Szeredi } 1088cbdf1e6SMiklos Szeredi 109451418fcSAndrew Gallagher /** 110451418fcSAndrew Gallagher * Mark the attributes as stale due to an atime change. Avoid the invalidate if 111451418fcSAndrew Gallagher * atime is not used. 112451418fcSAndrew Gallagher */ 113451418fcSAndrew Gallagher void fuse_invalidate_atime(struct inode *inode) 114451418fcSAndrew Gallagher { 115451418fcSAndrew Gallagher if (!IS_RDONLY(inode)) 116451418fcSAndrew Gallagher fuse_invalidate_attr(inode); 117451418fcSAndrew Gallagher } 118451418fcSAndrew Gallagher 1196f9f1180SMiklos Szeredi /* 1206f9f1180SMiklos Szeredi * Just mark the entry as stale, so that a next attempt to look it up 1216f9f1180SMiklos Szeredi * will result in a new lookup call to userspace 1226f9f1180SMiklos Szeredi * 1236f9f1180SMiklos Szeredi * This is called when a dentry is about to become negative and the 1246f9f1180SMiklos Szeredi * timeout is unknown (unlink, rmdir, rename and in some cases 1256f9f1180SMiklos Szeredi * lookup) 1266f9f1180SMiklos Szeredi */ 127dbd561d2SMiklos Szeredi void fuse_invalidate_entry_cache(struct dentry *entry) 1288cbdf1e6SMiklos Szeredi { 1290a0898cfSMiklos Szeredi fuse_dentry_settime(entry, 0); 1308cbdf1e6SMiklos Szeredi } 1318cbdf1e6SMiklos Szeredi 1326f9f1180SMiklos Szeredi /* 1336f9f1180SMiklos Szeredi * Same as fuse_invalidate_entry_cache(), but also try to remove the 1346f9f1180SMiklos Szeredi * dentry from the hash 1356f9f1180SMiklos Szeredi */ 1368cbdf1e6SMiklos Szeredi static void fuse_invalidate_entry(struct dentry *entry) 1378cbdf1e6SMiklos Szeredi { 1388cbdf1e6SMiklos Szeredi d_invalidate(entry); 1398cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 1400aa7c699SMiklos Szeredi } 1410aa7c699SMiklos Szeredi 1427078187aSMiklos Szeredi static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_args *args, 14313983d06SAl Viro u64 nodeid, const struct qstr *name, 144e5e5558eSMiklos Szeredi struct fuse_entry_out *outarg) 145e5e5558eSMiklos Szeredi { 1460e9663eeSMiklos Szeredi memset(outarg, 0, sizeof(struct fuse_entry_out)); 1477078187aSMiklos Szeredi args->in.h.opcode = FUSE_LOOKUP; 1487078187aSMiklos Szeredi args->in.h.nodeid = nodeid; 1497078187aSMiklos Szeredi args->in.numargs = 1; 1507078187aSMiklos Szeredi args->in.args[0].size = name->len + 1; 1517078187aSMiklos Szeredi args->in.args[0].value = name->name; 1527078187aSMiklos Szeredi args->out.numargs = 1; 1537078187aSMiklos Szeredi args->out.args[0].size = sizeof(struct fuse_entry_out); 1547078187aSMiklos Szeredi args->out.args[0].value = outarg; 155e5e5558eSMiklos Szeredi } 156e5e5558eSMiklos Szeredi 1575c5c5e51SMiklos Szeredi u64 fuse_get_attr_version(struct fuse_conn *fc) 1587dca9fd3SMiklos Szeredi { 1597dca9fd3SMiklos Szeredi u64 curr_version; 1607dca9fd3SMiklos Szeredi 1617dca9fd3SMiklos Szeredi /* 1627dca9fd3SMiklos Szeredi * The spin lock isn't actually needed on 64bit archs, but we 1637dca9fd3SMiklos Szeredi * don't yet care too much about such optimizations. 1647dca9fd3SMiklos Szeredi */ 1657dca9fd3SMiklos Szeredi spin_lock(&fc->lock); 1667dca9fd3SMiklos Szeredi curr_version = fc->attr_version; 1677dca9fd3SMiklos Szeredi spin_unlock(&fc->lock); 1687dca9fd3SMiklos Szeredi 1697dca9fd3SMiklos Szeredi return curr_version; 1707dca9fd3SMiklos Szeredi } 1717dca9fd3SMiklos Szeredi 1726f9f1180SMiklos Szeredi /* 1736f9f1180SMiklos Szeredi * Check whether the dentry is still valid 1746f9f1180SMiklos Szeredi * 1756f9f1180SMiklos Szeredi * If the entry validity timeout has expired and the dentry is 1766f9f1180SMiklos Szeredi * positive, try to redo the lookup. If the lookup results in a 1776f9f1180SMiklos Szeredi * different inode, then let the VFS invalidate the dentry and redo 1786f9f1180SMiklos Szeredi * the lookup once more. If the lookup results in the same inode, 1796f9f1180SMiklos Szeredi * then refresh the attributes, timeouts and mark the dentry valid. 1806f9f1180SMiklos Szeredi */ 1810b728e19SAl Viro static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) 182e5e5558eSMiklos Szeredi { 18334286d66SNick Piggin struct inode *inode; 18428420dadSMiklos Szeredi struct dentry *parent; 18528420dadSMiklos Szeredi struct fuse_conn *fc; 1866314efeeSMiklos Szeredi struct fuse_inode *fi; 187e2a6b952SMiklos Szeredi int ret; 1888cbdf1e6SMiklos Szeredi 1892b0143b5SDavid Howells inode = d_inode_rcu(entry); 1908cbdf1e6SMiklos Szeredi if (inode && is_bad_inode(inode)) 191e2a6b952SMiklos Szeredi goto invalid; 192154210ccSAnand Avati else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) || 193154210ccSAnand Avati (flags & LOOKUP_REVAL)) { 194e5e5558eSMiklos Szeredi struct fuse_entry_out outarg; 1957078187aSMiklos Szeredi FUSE_ARGS(args); 19607e77dcaSMiklos Szeredi struct fuse_forget_link *forget; 1971fb69e78SMiklos Szeredi u64 attr_version; 1988cbdf1e6SMiklos Szeredi 19950322fe7SMiklos Szeredi /* For negative dentries, always do a fresh lookup */ 2008cbdf1e6SMiklos Szeredi if (!inode) 201e2a6b952SMiklos Szeredi goto invalid; 2028cbdf1e6SMiklos Szeredi 203e2a6b952SMiklos Szeredi ret = -ECHILD; 2040b728e19SAl Viro if (flags & LOOKUP_RCU) 205e2a6b952SMiklos Szeredi goto out; 206e7c0a167SMiklos Szeredi 2078cbdf1e6SMiklos Szeredi fc = get_fuse_conn(inode); 208e5e5558eSMiklos Szeredi 20907e77dcaSMiklos Szeredi forget = fuse_alloc_forget(); 210e2a6b952SMiklos Szeredi ret = -ENOMEM; 2117078187aSMiklos Szeredi if (!forget) 212e2a6b952SMiklos Szeredi goto out; 2132d51013eSMiklos Szeredi 2147dca9fd3SMiklos Szeredi attr_version = fuse_get_attr_version(fc); 2151fb69e78SMiklos Szeredi 216e956edd0SMiklos Szeredi parent = dget_parent(entry); 2172b0143b5SDavid Howells fuse_lookup_init(fc, &args, get_node_id(d_inode(parent)), 218c180eebeSMiklos Szeredi &entry->d_name, &outarg); 2197078187aSMiklos Szeredi ret = fuse_simple_request(fc, &args); 220e956edd0SMiklos Szeredi dput(parent); 22150322fe7SMiklos Szeredi /* Zero nodeid is same as -ENOENT */ 2227078187aSMiklos Szeredi if (!ret && !outarg.nodeid) 2237078187aSMiklos Szeredi ret = -ENOENT; 2247078187aSMiklos Szeredi if (!ret) { 2256314efeeSMiklos Szeredi fi = get_fuse_inode(inode); 2269e6268dbSMiklos Szeredi if (outarg.nodeid != get_node_id(inode)) { 22707e77dcaSMiklos Szeredi fuse_queue_forget(fc, forget, outarg.nodeid, 1); 228e2a6b952SMiklos Szeredi goto invalid; 2299e6268dbSMiklos Szeredi } 2308da5ff23SMiklos Szeredi spin_lock(&fc->lock); 2319e6268dbSMiklos Szeredi fi->nlookup++; 2328da5ff23SMiklos Szeredi spin_unlock(&fc->lock); 2339e6268dbSMiklos Szeredi } 23407e77dcaSMiklos Szeredi kfree(forget); 2357078187aSMiklos Szeredi if (ret == -ENOMEM) 2367078187aSMiklos Szeredi goto out; 2377078187aSMiklos Szeredi if (ret || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) 238e2a6b952SMiklos Szeredi goto invalid; 239e5e5558eSMiklos Szeredi 24060bcc88aSSeth Forshee forget_all_cached_acls(inode); 2411fb69e78SMiklos Szeredi fuse_change_attributes(inode, &outarg.attr, 2421fb69e78SMiklos Szeredi entry_attr_timeout(&outarg), 2431fb69e78SMiklos Szeredi attr_version); 2441fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outarg); 24528420dadSMiklos Szeredi } else if (inode) { 2466314efeeSMiklos Szeredi fi = get_fuse_inode(inode); 2476314efeeSMiklos Szeredi if (flags & LOOKUP_RCU) { 2486314efeeSMiklos Szeredi if (test_bit(FUSE_I_INIT_RDPLUS, &fi->state)) 2496314efeeSMiklos Szeredi return -ECHILD; 2506314efeeSMiklos Szeredi } else if (test_and_clear_bit(FUSE_I_INIT_RDPLUS, &fi->state)) { 25128420dadSMiklos Szeredi parent = dget_parent(entry); 2522b0143b5SDavid Howells fuse_advise_use_readdirplus(d_inode(parent)); 25328420dadSMiklos Szeredi dput(parent); 254e5e5558eSMiklos Szeredi } 25528420dadSMiklos Szeredi } 256e2a6b952SMiklos Szeredi ret = 1; 257e2a6b952SMiklos Szeredi out: 258e2a6b952SMiklos Szeredi return ret; 259e2a6b952SMiklos Szeredi 260e2a6b952SMiklos Szeredi invalid: 261e2a6b952SMiklos Szeredi ret = 0; 262e2a6b952SMiklos Szeredi goto out; 263e5e5558eSMiklos Szeredi } 264e5e5558eSMiklos Szeredi 2658bfc016dSMiklos Szeredi static int invalid_nodeid(u64 nodeid) 2662827d0b2SMiklos Szeredi { 2672827d0b2SMiklos Szeredi return !nodeid || nodeid == FUSE_ROOT_ID; 2682827d0b2SMiklos Szeredi } 2692827d0b2SMiklos Szeredi 270f75fdf22SMiklos Szeredi static int fuse_dentry_init(struct dentry *dentry) 271f75fdf22SMiklos Szeredi { 272f75fdf22SMiklos Szeredi dentry->d_fsdata = kzalloc(sizeof(union fuse_dentry), GFP_KERNEL); 273f75fdf22SMiklos Szeredi 274f75fdf22SMiklos Szeredi return dentry->d_fsdata ? 0 : -ENOMEM; 275f75fdf22SMiklos Szeredi } 276f75fdf22SMiklos Szeredi static void fuse_dentry_release(struct dentry *dentry) 277f75fdf22SMiklos Szeredi { 278f75fdf22SMiklos Szeredi union fuse_dentry *fd = dentry->d_fsdata; 279f75fdf22SMiklos Szeredi 280f75fdf22SMiklos Szeredi kfree_rcu(fd, rcu); 281f75fdf22SMiklos Szeredi } 282f75fdf22SMiklos Szeredi 2834269590aSAl Viro const struct dentry_operations fuse_dentry_operations = { 284e5e5558eSMiklos Szeredi .d_revalidate = fuse_dentry_revalidate, 285f75fdf22SMiklos Szeredi .d_init = fuse_dentry_init, 286f75fdf22SMiklos Szeredi .d_release = fuse_dentry_release, 287e5e5558eSMiklos Szeredi }; 288e5e5558eSMiklos Szeredi 2890ce267ffSMiklos Szeredi const struct dentry_operations fuse_root_dentry_operations = { 2900ce267ffSMiklos Szeredi .d_init = fuse_dentry_init, 2910ce267ffSMiklos Szeredi .d_release = fuse_dentry_release, 2920ce267ffSMiklos Szeredi }; 2930ce267ffSMiklos Szeredi 294a5bfffacSTimo Savola int fuse_valid_type(int m) 29539ee059aSMiklos Szeredi { 29639ee059aSMiklos Szeredi return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) || 29739ee059aSMiklos Szeredi S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); 29839ee059aSMiklos Szeredi } 29939ee059aSMiklos Szeredi 30013983d06SAl Viro int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name, 301c180eebeSMiklos Szeredi struct fuse_entry_out *outarg, struct inode **inode) 302c180eebeSMiklos Szeredi { 303c180eebeSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(sb); 3047078187aSMiklos Szeredi FUSE_ARGS(args); 30507e77dcaSMiklos Szeredi struct fuse_forget_link *forget; 306c180eebeSMiklos Szeredi u64 attr_version; 307c180eebeSMiklos Szeredi int err; 308c180eebeSMiklos Szeredi 309c180eebeSMiklos Szeredi *inode = NULL; 310c180eebeSMiklos Szeredi err = -ENAMETOOLONG; 311c180eebeSMiklos Szeredi if (name->len > FUSE_NAME_MAX) 312c180eebeSMiklos Szeredi goto out; 313c180eebeSMiklos Szeredi 314c180eebeSMiklos Szeredi 31507e77dcaSMiklos Szeredi forget = fuse_alloc_forget(); 31607e77dcaSMiklos Szeredi err = -ENOMEM; 3177078187aSMiklos Szeredi if (!forget) 318c180eebeSMiklos Szeredi goto out; 319c180eebeSMiklos Szeredi 320c180eebeSMiklos Szeredi attr_version = fuse_get_attr_version(fc); 321c180eebeSMiklos Szeredi 3227078187aSMiklos Szeredi fuse_lookup_init(fc, &args, nodeid, name, outarg); 3237078187aSMiklos Szeredi err = fuse_simple_request(fc, &args); 324c180eebeSMiklos Szeredi /* Zero nodeid is same as -ENOENT, but with valid timeout */ 325c180eebeSMiklos Szeredi if (err || !outarg->nodeid) 326c180eebeSMiklos Szeredi goto out_put_forget; 327c180eebeSMiklos Szeredi 328c180eebeSMiklos Szeredi err = -EIO; 329c180eebeSMiklos Szeredi if (!outarg->nodeid) 330c180eebeSMiklos Szeredi goto out_put_forget; 331c180eebeSMiklos Szeredi if (!fuse_valid_type(outarg->attr.mode)) 332c180eebeSMiklos Szeredi goto out_put_forget; 333c180eebeSMiklos Szeredi 334c180eebeSMiklos Szeredi *inode = fuse_iget(sb, outarg->nodeid, outarg->generation, 335c180eebeSMiklos Szeredi &outarg->attr, entry_attr_timeout(outarg), 336c180eebeSMiklos Szeredi attr_version); 337c180eebeSMiklos Szeredi err = -ENOMEM; 338c180eebeSMiklos Szeredi if (!*inode) { 33907e77dcaSMiklos Szeredi fuse_queue_forget(fc, forget, outarg->nodeid, 1); 340c180eebeSMiklos Szeredi goto out; 341c180eebeSMiklos Szeredi } 342c180eebeSMiklos Szeredi err = 0; 343c180eebeSMiklos Szeredi 344c180eebeSMiklos Szeredi out_put_forget: 34507e77dcaSMiklos Szeredi kfree(forget); 346c180eebeSMiklos Szeredi out: 347c180eebeSMiklos Szeredi return err; 348c180eebeSMiklos Szeredi } 349c180eebeSMiklos Szeredi 3500aa7c699SMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, 35100cd8dd3SAl Viro unsigned int flags) 352e5e5558eSMiklos Szeredi { 353e5e5558eSMiklos Szeredi int err; 354e5e5558eSMiklos Szeredi struct fuse_entry_out outarg; 355c180eebeSMiklos Szeredi struct inode *inode; 3560de6256dSMiklos Szeredi struct dentry *newent; 357c180eebeSMiklos Szeredi bool outarg_valid = true; 358e5e5558eSMiklos Szeredi 3595c672ab3SMiklos Szeredi fuse_lock_inode(dir); 360c180eebeSMiklos Szeredi err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name, 361c180eebeSMiklos Szeredi &outarg, &inode); 3625c672ab3SMiklos Szeredi fuse_unlock_inode(dir); 363c180eebeSMiklos Szeredi if (err == -ENOENT) { 364c180eebeSMiklos Szeredi outarg_valid = false; 365c180eebeSMiklos Szeredi err = 0; 3662d51013eSMiklos Szeredi } 367c180eebeSMiklos Szeredi if (err) 368c180eebeSMiklos Szeredi goto out_err; 3692d51013eSMiklos Szeredi 370ee4e5271SMiklos Szeredi err = -EIO; 371c180eebeSMiklos Szeredi if (inode && get_node_id(inode) == FUSE_ROOT_ID) 372c180eebeSMiklos Szeredi goto out_iput; 373e5e5558eSMiklos Szeredi 37441d28bcaSAl Viro newent = d_splice_alias(inode, entry); 375c180eebeSMiklos Szeredi err = PTR_ERR(newent); 376c180eebeSMiklos Szeredi if (IS_ERR(newent)) 3775835f339SMiklos Szeredi goto out_err; 378d2a85164SMiklos Szeredi 3790de6256dSMiklos Szeredi entry = newent ? newent : entry; 380c180eebeSMiklos Szeredi if (outarg_valid) 3811fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outarg); 3828cbdf1e6SMiklos Szeredi else 3838cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 384c180eebeSMiklos Szeredi 3854582a4abSFeng Shuo fuse_advise_use_readdirplus(dir); 3860de6256dSMiklos Szeredi return newent; 387c180eebeSMiklos Szeredi 388c180eebeSMiklos Szeredi out_iput: 389c180eebeSMiklos Szeredi iput(inode); 390c180eebeSMiklos Szeredi out_err: 391c180eebeSMiklos Szeredi return ERR_PTR(err); 392e5e5558eSMiklos Szeredi } 393e5e5558eSMiklos Szeredi 3946f9f1180SMiklos Szeredi /* 3956f9f1180SMiklos Szeredi * Atomic create+open operation 3966f9f1180SMiklos Szeredi * 3976f9f1180SMiklos Szeredi * If the filesystem doesn't support this, then fall back to separate 3986f9f1180SMiklos Szeredi * 'mknod' + 'open' requests. 3996f9f1180SMiklos Szeredi */ 400d9585277SAl Viro static int fuse_create_open(struct inode *dir, struct dentry *entry, 40130d90494SAl Viro struct file *file, unsigned flags, 40247237687SAl Viro umode_t mode, int *opened) 403fd72faacSMiklos Szeredi { 404fd72faacSMiklos Szeredi int err; 405fd72faacSMiklos Szeredi struct inode *inode; 406fd72faacSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 4077078187aSMiklos Szeredi FUSE_ARGS(args); 40807e77dcaSMiklos Szeredi struct fuse_forget_link *forget; 409e0a43ddcSMiklos Szeredi struct fuse_create_in inarg; 410fd72faacSMiklos Szeredi struct fuse_open_out outopen; 411fd72faacSMiklos Szeredi struct fuse_entry_out outentry; 412fd72faacSMiklos Szeredi struct fuse_file *ff; 413fd72faacSMiklos Szeredi 414af109bcaSMiklos Szeredi /* Userspace expects S_IFREG in create mode */ 415af109bcaSMiklos Szeredi BUG_ON((mode & S_IFMT) != S_IFREG); 416af109bcaSMiklos Szeredi 41707e77dcaSMiklos Szeredi forget = fuse_alloc_forget(); 418c8ccbe03SMiklos Szeredi err = -ENOMEM; 41907e77dcaSMiklos Szeredi if (!forget) 420c8ccbe03SMiklos Szeredi goto out_err; 42151eb01e7SMiklos Szeredi 422ce1d5a49SMiklos Szeredi err = -ENOMEM; 423acf99433STejun Heo ff = fuse_file_alloc(fc); 424fd72faacSMiklos Szeredi if (!ff) 4257078187aSMiklos Szeredi goto out_put_forget_req; 426fd72faacSMiklos Szeredi 427e0a43ddcSMiklos Szeredi if (!fc->dont_mask) 428e0a43ddcSMiklos Szeredi mode &= ~current_umask(); 429e0a43ddcSMiklos Szeredi 430fd72faacSMiklos Szeredi flags &= ~O_NOCTTY; 431fd72faacSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 4320e9663eeSMiklos Szeredi memset(&outentry, 0, sizeof(outentry)); 433fd72faacSMiklos Szeredi inarg.flags = flags; 434fd72faacSMiklos Szeredi inarg.mode = mode; 435e0a43ddcSMiklos Szeredi inarg.umask = current_umask(); 4367078187aSMiklos Szeredi args.in.h.opcode = FUSE_CREATE; 4377078187aSMiklos Szeredi args.in.h.nodeid = get_node_id(dir); 4387078187aSMiklos Szeredi args.in.numargs = 2; 43921f62174SMiklos Szeredi args.in.args[0].size = sizeof(inarg); 4407078187aSMiklos Szeredi args.in.args[0].value = &inarg; 4417078187aSMiklos Szeredi args.in.args[1].size = entry->d_name.len + 1; 4427078187aSMiklos Szeredi args.in.args[1].value = entry->d_name.name; 4437078187aSMiklos Szeredi args.out.numargs = 2; 4447078187aSMiklos Szeredi args.out.args[0].size = sizeof(outentry); 4457078187aSMiklos Szeredi args.out.args[0].value = &outentry; 4467078187aSMiklos Szeredi args.out.args[1].size = sizeof(outopen); 4477078187aSMiklos Szeredi args.out.args[1].value = &outopen; 4487078187aSMiklos Szeredi err = fuse_simple_request(fc, &args); 449c8ccbe03SMiklos Szeredi if (err) 450fd72faacSMiklos Szeredi goto out_free_ff; 451fd72faacSMiklos Szeredi 452fd72faacSMiklos Szeredi err = -EIO; 4532827d0b2SMiklos Szeredi if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid)) 454fd72faacSMiklos Szeredi goto out_free_ff; 455fd72faacSMiklos Szeredi 456c7b7143cSMiklos Szeredi ff->fh = outopen.fh; 457c7b7143cSMiklos Szeredi ff->nodeid = outentry.nodeid; 458c7b7143cSMiklos Szeredi ff->open_flags = outopen.open_flags; 459fd72faacSMiklos Szeredi inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, 4601fb69e78SMiklos Szeredi &outentry.attr, entry_attr_timeout(&outentry), 0); 461fd72faacSMiklos Szeredi if (!inode) { 462fd72faacSMiklos Szeredi flags &= ~(O_CREAT | O_EXCL | O_TRUNC); 4638b0797a4SMiklos Szeredi fuse_sync_release(ff, flags); 46407e77dcaSMiklos Szeredi fuse_queue_forget(fc, forget, outentry.nodeid, 1); 465c8ccbe03SMiklos Szeredi err = -ENOMEM; 466c8ccbe03SMiklos Szeredi goto out_err; 467fd72faacSMiklos Szeredi } 46807e77dcaSMiklos Szeredi kfree(forget); 469fd72faacSMiklos Szeredi d_instantiate(entry, inode); 4701fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outentry); 4710952b2a4SMiklos Szeredi fuse_invalidate_attr(dir); 47230d90494SAl Viro err = finish_open(file, entry, generic_file_open, opened); 47330d90494SAl Viro if (err) { 4748b0797a4SMiklos Szeredi fuse_sync_release(ff, flags); 475c8ccbe03SMiklos Szeredi } else { 476267d8444SMiklos Szeredi file->private_data = ff; 477c7b7143cSMiklos Szeredi fuse_finish_open(inode, file); 478c8ccbe03SMiklos Szeredi } 479d9585277SAl Viro return err; 480fd72faacSMiklos Szeredi 481fd72faacSMiklos Szeredi out_free_ff: 482fd72faacSMiklos Szeredi fuse_file_free(ff); 48351eb01e7SMiklos Szeredi out_put_forget_req: 48407e77dcaSMiklos Szeredi kfree(forget); 485c8ccbe03SMiklos Szeredi out_err: 486d9585277SAl Viro return err; 487c8ccbe03SMiklos Szeredi } 488c8ccbe03SMiklos Szeredi 489c8ccbe03SMiklos Szeredi static int fuse_mknod(struct inode *, struct dentry *, umode_t, dev_t); 490d9585277SAl Viro static int fuse_atomic_open(struct inode *dir, struct dentry *entry, 49130d90494SAl Viro struct file *file, unsigned flags, 49247237687SAl Viro umode_t mode, int *opened) 493c8ccbe03SMiklos Szeredi { 494c8ccbe03SMiklos Szeredi int err; 495c8ccbe03SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 496c8ccbe03SMiklos Szeredi struct dentry *res = NULL; 497c8ccbe03SMiklos Szeredi 49800699ad8SAl Viro if (d_in_lookup(entry)) { 49900cd8dd3SAl Viro res = fuse_lookup(dir, entry, 0); 500c8ccbe03SMiklos Szeredi if (IS_ERR(res)) 501d9585277SAl Viro return PTR_ERR(res); 502c8ccbe03SMiklos Szeredi 503c8ccbe03SMiklos Szeredi if (res) 504c8ccbe03SMiklos Szeredi entry = res; 505c8ccbe03SMiklos Szeredi } 506c8ccbe03SMiklos Szeredi 5072b0143b5SDavid Howells if (!(flags & O_CREAT) || d_really_is_positive(entry)) 508c8ccbe03SMiklos Szeredi goto no_open; 509c8ccbe03SMiklos Szeredi 510c8ccbe03SMiklos Szeredi /* Only creates */ 51147237687SAl Viro *opened |= FILE_CREATED; 512c8ccbe03SMiklos Szeredi 513c8ccbe03SMiklos Szeredi if (fc->no_create) 514c8ccbe03SMiklos Szeredi goto mknod; 515c8ccbe03SMiklos Szeredi 51630d90494SAl Viro err = fuse_create_open(dir, entry, file, flags, mode, opened); 517d9585277SAl Viro if (err == -ENOSYS) { 518c8ccbe03SMiklos Szeredi fc->no_create = 1; 519c8ccbe03SMiklos Szeredi goto mknod; 520c8ccbe03SMiklos Szeredi } 521c8ccbe03SMiklos Szeredi out_dput: 522c8ccbe03SMiklos Szeredi dput(res); 523d9585277SAl Viro return err; 524c8ccbe03SMiklos Szeredi 525c8ccbe03SMiklos Szeredi mknod: 526c8ccbe03SMiklos Szeredi err = fuse_mknod(dir, entry, mode, 0); 527d9585277SAl Viro if (err) 528c8ccbe03SMiklos Szeredi goto out_dput; 529c8ccbe03SMiklos Szeredi no_open: 530e45198a6SAl Viro return finish_no_open(file, res); 531fd72faacSMiklos Szeredi } 532fd72faacSMiklos Szeredi 5336f9f1180SMiklos Szeredi /* 5346f9f1180SMiklos Szeredi * Code shared between mknod, mkdir, symlink and link 5356f9f1180SMiklos Szeredi */ 5367078187aSMiklos Szeredi static int create_new_entry(struct fuse_conn *fc, struct fuse_args *args, 5379e6268dbSMiklos Szeredi struct inode *dir, struct dentry *entry, 538541af6a0SAl Viro umode_t mode) 5399e6268dbSMiklos Szeredi { 5409e6268dbSMiklos Szeredi struct fuse_entry_out outarg; 5419e6268dbSMiklos Szeredi struct inode *inode; 5429e6268dbSMiklos Szeredi int err; 54307e77dcaSMiklos Szeredi struct fuse_forget_link *forget; 5442d51013eSMiklos Szeredi 54507e77dcaSMiklos Szeredi forget = fuse_alloc_forget(); 5467078187aSMiklos Szeredi if (!forget) 54707e77dcaSMiklos Szeredi return -ENOMEM; 5489e6268dbSMiklos Szeredi 5490e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 5507078187aSMiklos Szeredi args->in.h.nodeid = get_node_id(dir); 5517078187aSMiklos Szeredi args->out.numargs = 1; 5527078187aSMiklos Szeredi args->out.args[0].size = sizeof(outarg); 5537078187aSMiklos Szeredi args->out.args[0].value = &outarg; 5547078187aSMiklos Szeredi err = fuse_simple_request(fc, args); 5552d51013eSMiklos Szeredi if (err) 5562d51013eSMiklos Szeredi goto out_put_forget_req; 5572d51013eSMiklos Szeredi 55839ee059aSMiklos Szeredi err = -EIO; 55939ee059aSMiklos Szeredi if (invalid_nodeid(outarg.nodeid)) 5602d51013eSMiklos Szeredi goto out_put_forget_req; 56139ee059aSMiklos Szeredi 56239ee059aSMiklos Szeredi if ((outarg.attr.mode ^ mode) & S_IFMT) 5632d51013eSMiklos Szeredi goto out_put_forget_req; 56439ee059aSMiklos Szeredi 5659e6268dbSMiklos Szeredi inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 5661fb69e78SMiklos Szeredi &outarg.attr, entry_attr_timeout(&outarg), 0); 5679e6268dbSMiklos Szeredi if (!inode) { 56807e77dcaSMiklos Szeredi fuse_queue_forget(fc, forget, outarg.nodeid, 1); 5699e6268dbSMiklos Szeredi return -ENOMEM; 5709e6268dbSMiklos Szeredi } 57107e77dcaSMiklos Szeredi kfree(forget); 5729e6268dbSMiklos Szeredi 573b70a80e7SMiklos Szeredi err = d_instantiate_no_diralias(entry, inode); 574b70a80e7SMiklos Szeredi if (err) 575b70a80e7SMiklos Szeredi return err; 576d2a85164SMiklos Szeredi 5771fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outarg); 5789e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 5799e6268dbSMiklos Szeredi return 0; 58039ee059aSMiklos Szeredi 5812d51013eSMiklos Szeredi out_put_forget_req: 58207e77dcaSMiklos Szeredi kfree(forget); 58339ee059aSMiklos Szeredi return err; 5849e6268dbSMiklos Szeredi } 5859e6268dbSMiklos Szeredi 5861a67aafbSAl Viro static int fuse_mknod(struct inode *dir, struct dentry *entry, umode_t mode, 5879e6268dbSMiklos Szeredi dev_t rdev) 5889e6268dbSMiklos Szeredi { 5899e6268dbSMiklos Szeredi struct fuse_mknod_in inarg; 5909e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 5917078187aSMiklos Szeredi FUSE_ARGS(args); 5929e6268dbSMiklos Szeredi 593e0a43ddcSMiklos Szeredi if (!fc->dont_mask) 594e0a43ddcSMiklos Szeredi mode &= ~current_umask(); 595e0a43ddcSMiklos Szeredi 5969e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 5979e6268dbSMiklos Szeredi inarg.mode = mode; 5989e6268dbSMiklos Szeredi inarg.rdev = new_encode_dev(rdev); 599e0a43ddcSMiklos Szeredi inarg.umask = current_umask(); 6007078187aSMiklos Szeredi args.in.h.opcode = FUSE_MKNOD; 6017078187aSMiklos Szeredi args.in.numargs = 2; 60221f62174SMiklos Szeredi args.in.args[0].size = sizeof(inarg); 6037078187aSMiklos Szeredi args.in.args[0].value = &inarg; 6047078187aSMiklos Szeredi args.in.args[1].size = entry->d_name.len + 1; 6057078187aSMiklos Szeredi args.in.args[1].value = entry->d_name.name; 6067078187aSMiklos Szeredi return create_new_entry(fc, &args, dir, entry, mode); 6079e6268dbSMiklos Szeredi } 6089e6268dbSMiklos Szeredi 6094acdaf27SAl Viro static int fuse_create(struct inode *dir, struct dentry *entry, umode_t mode, 610ebfc3b49SAl Viro bool excl) 6119e6268dbSMiklos Szeredi { 6129e6268dbSMiklos Szeredi return fuse_mknod(dir, entry, mode, 0); 6139e6268dbSMiklos Szeredi } 6149e6268dbSMiklos Szeredi 61518bb1db3SAl Viro static int fuse_mkdir(struct inode *dir, struct dentry *entry, umode_t mode) 6169e6268dbSMiklos Szeredi { 6179e6268dbSMiklos Szeredi struct fuse_mkdir_in inarg; 6189e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 6197078187aSMiklos Szeredi FUSE_ARGS(args); 6209e6268dbSMiklos Szeredi 621e0a43ddcSMiklos Szeredi if (!fc->dont_mask) 622e0a43ddcSMiklos Szeredi mode &= ~current_umask(); 623e0a43ddcSMiklos Szeredi 6249e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 6259e6268dbSMiklos Szeredi inarg.mode = mode; 626e0a43ddcSMiklos Szeredi inarg.umask = current_umask(); 6277078187aSMiklos Szeredi args.in.h.opcode = FUSE_MKDIR; 6287078187aSMiklos Szeredi args.in.numargs = 2; 6297078187aSMiklos Szeredi args.in.args[0].size = sizeof(inarg); 6307078187aSMiklos Szeredi args.in.args[0].value = &inarg; 6317078187aSMiklos Szeredi args.in.args[1].size = entry->d_name.len + 1; 6327078187aSMiklos Szeredi args.in.args[1].value = entry->d_name.name; 6337078187aSMiklos Szeredi return create_new_entry(fc, &args, dir, entry, S_IFDIR); 6349e6268dbSMiklos Szeredi } 6359e6268dbSMiklos Szeredi 6369e6268dbSMiklos Szeredi static int fuse_symlink(struct inode *dir, struct dentry *entry, 6379e6268dbSMiklos Szeredi const char *link) 6389e6268dbSMiklos Szeredi { 6399e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 6409e6268dbSMiklos Szeredi unsigned len = strlen(link) + 1; 6417078187aSMiklos Szeredi FUSE_ARGS(args); 6429e6268dbSMiklos Szeredi 6437078187aSMiklos Szeredi args.in.h.opcode = FUSE_SYMLINK; 6447078187aSMiklos Szeredi args.in.numargs = 2; 6457078187aSMiklos Szeredi args.in.args[0].size = entry->d_name.len + 1; 6467078187aSMiklos Szeredi args.in.args[0].value = entry->d_name.name; 6477078187aSMiklos Szeredi args.in.args[1].size = len; 6487078187aSMiklos Szeredi args.in.args[1].value = link; 6497078187aSMiklos Szeredi return create_new_entry(fc, &args, dir, entry, S_IFLNK); 6509e6268dbSMiklos Szeredi } 6519e6268dbSMiklos Szeredi 652703c7362SSeth Forshee void fuse_update_ctime(struct inode *inode) 65331f3267bSMaxim Patlasov { 65431f3267bSMaxim Patlasov if (!IS_NOCMTIME(inode)) { 655c2050a45SDeepa Dinamani inode->i_ctime = current_time(inode); 65631f3267bSMaxim Patlasov mark_inode_dirty_sync(inode); 65731f3267bSMaxim Patlasov } 65831f3267bSMaxim Patlasov } 65931f3267bSMaxim Patlasov 6609e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry) 6619e6268dbSMiklos Szeredi { 6629e6268dbSMiklos Szeredi int err; 6639e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 6647078187aSMiklos Szeredi FUSE_ARGS(args); 6659e6268dbSMiklos Szeredi 6667078187aSMiklos Szeredi args.in.h.opcode = FUSE_UNLINK; 6677078187aSMiklos Szeredi args.in.h.nodeid = get_node_id(dir); 6687078187aSMiklos Szeredi args.in.numargs = 1; 6697078187aSMiklos Szeredi args.in.args[0].size = entry->d_name.len + 1; 6707078187aSMiklos Szeredi args.in.args[0].value = entry->d_name.name; 6717078187aSMiklos Szeredi err = fuse_simple_request(fc, &args); 6729e6268dbSMiklos Szeredi if (!err) { 6732b0143b5SDavid Howells struct inode *inode = d_inode(entry); 674ac45d613SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 6759e6268dbSMiklos Szeredi 676ac45d613SMiklos Szeredi spin_lock(&fc->lock); 677ac45d613SMiklos Szeredi fi->attr_version = ++fc->attr_version; 678dfca7cebSMiklos Szeredi /* 679dfca7cebSMiklos Szeredi * If i_nlink == 0 then unlink doesn't make sense, yet this can 680dfca7cebSMiklos Szeredi * happen if userspace filesystem is careless. It would be 681dfca7cebSMiklos Szeredi * difficult to enforce correct nlink usage so just ignore this 682dfca7cebSMiklos Szeredi * condition here 683dfca7cebSMiklos Szeredi */ 684dfca7cebSMiklos Szeredi if (inode->i_nlink > 0) 685ac45d613SMiklos Szeredi drop_nlink(inode); 686ac45d613SMiklos Szeredi spin_unlock(&fc->lock); 6879e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 6889e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 6898cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 69031f3267bSMaxim Patlasov fuse_update_ctime(inode); 6919e6268dbSMiklos Szeredi } else if (err == -EINTR) 6929e6268dbSMiklos Szeredi fuse_invalidate_entry(entry); 6939e6268dbSMiklos Szeredi return err; 6949e6268dbSMiklos Szeredi } 6959e6268dbSMiklos Szeredi 6969e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry) 6979e6268dbSMiklos Szeredi { 6989e6268dbSMiklos Szeredi int err; 6999e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 7007078187aSMiklos Szeredi FUSE_ARGS(args); 7019e6268dbSMiklos Szeredi 7027078187aSMiklos Szeredi args.in.h.opcode = FUSE_RMDIR; 7037078187aSMiklos Szeredi args.in.h.nodeid = get_node_id(dir); 7047078187aSMiklos Szeredi args.in.numargs = 1; 7057078187aSMiklos Szeredi args.in.args[0].size = entry->d_name.len + 1; 7067078187aSMiklos Szeredi args.in.args[0].value = entry->d_name.name; 7077078187aSMiklos Szeredi err = fuse_simple_request(fc, &args); 7089e6268dbSMiklos Szeredi if (!err) { 7092b0143b5SDavid Howells clear_nlink(d_inode(entry)); 7109e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 7118cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 7129e6268dbSMiklos Szeredi } else if (err == -EINTR) 7139e6268dbSMiklos Szeredi fuse_invalidate_entry(entry); 7149e6268dbSMiklos Szeredi return err; 7159e6268dbSMiklos Szeredi } 7169e6268dbSMiklos Szeredi 7171560c974SMiklos Szeredi static int fuse_rename_common(struct inode *olddir, struct dentry *oldent, 7181560c974SMiklos Szeredi struct inode *newdir, struct dentry *newent, 7191560c974SMiklos Szeredi unsigned int flags, int opcode, size_t argsize) 7209e6268dbSMiklos Szeredi { 7219e6268dbSMiklos Szeredi int err; 7221560c974SMiklos Szeredi struct fuse_rename2_in inarg; 7239e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(olddir); 7247078187aSMiklos Szeredi FUSE_ARGS(args); 7259e6268dbSMiklos Szeredi 7261560c974SMiklos Szeredi memset(&inarg, 0, argsize); 7279e6268dbSMiklos Szeredi inarg.newdir = get_node_id(newdir); 7281560c974SMiklos Szeredi inarg.flags = flags; 7297078187aSMiklos Szeredi args.in.h.opcode = opcode; 7307078187aSMiklos Szeredi args.in.h.nodeid = get_node_id(olddir); 7317078187aSMiklos Szeredi args.in.numargs = 3; 7327078187aSMiklos Szeredi args.in.args[0].size = argsize; 7337078187aSMiklos Szeredi args.in.args[0].value = &inarg; 7347078187aSMiklos Szeredi args.in.args[1].size = oldent->d_name.len + 1; 7357078187aSMiklos Szeredi args.in.args[1].value = oldent->d_name.name; 7367078187aSMiklos Szeredi args.in.args[2].size = newent->d_name.len + 1; 7377078187aSMiklos Szeredi args.in.args[2].value = newent->d_name.name; 7387078187aSMiklos Szeredi err = fuse_simple_request(fc, &args); 7399e6268dbSMiklos Szeredi if (!err) { 74008b63307SMiklos Szeredi /* ctime changes */ 7412b0143b5SDavid Howells fuse_invalidate_attr(d_inode(oldent)); 7422b0143b5SDavid Howells fuse_update_ctime(d_inode(oldent)); 74308b63307SMiklos Szeredi 7441560c974SMiklos Szeredi if (flags & RENAME_EXCHANGE) { 7452b0143b5SDavid Howells fuse_invalidate_attr(d_inode(newent)); 7462b0143b5SDavid Howells fuse_update_ctime(d_inode(newent)); 7471560c974SMiklos Szeredi } 7481560c974SMiklos Szeredi 7499e6268dbSMiklos Szeredi fuse_invalidate_attr(olddir); 7509e6268dbSMiklos Szeredi if (olddir != newdir) 7519e6268dbSMiklos Szeredi fuse_invalidate_attr(newdir); 7528cbdf1e6SMiklos Szeredi 7538cbdf1e6SMiklos Szeredi /* newent will end up negative */ 7542b0143b5SDavid Howells if (!(flags & RENAME_EXCHANGE) && d_really_is_positive(newent)) { 7552b0143b5SDavid Howells fuse_invalidate_attr(d_inode(newent)); 7568cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(newent); 7572b0143b5SDavid Howells fuse_update_ctime(d_inode(newent)); 7585219f346SMiklos Szeredi } 7599e6268dbSMiklos Szeredi } else if (err == -EINTR) { 7609e6268dbSMiklos Szeredi /* If request was interrupted, DEITY only knows if the 7619e6268dbSMiklos Szeredi rename actually took place. If the invalidation 7629e6268dbSMiklos Szeredi fails (e.g. some process has CWD under the renamed 7639e6268dbSMiklos Szeredi directory), then there can be inconsistency between 7649e6268dbSMiklos Szeredi the dcache and the real filesystem. Tough luck. */ 7659e6268dbSMiklos Szeredi fuse_invalidate_entry(oldent); 7662b0143b5SDavid Howells if (d_really_is_positive(newent)) 7679e6268dbSMiklos Szeredi fuse_invalidate_entry(newent); 7689e6268dbSMiklos Szeredi } 7699e6268dbSMiklos Szeredi 7709e6268dbSMiklos Szeredi return err; 7719e6268dbSMiklos Szeredi } 7729e6268dbSMiklos Szeredi 7731560c974SMiklos Szeredi static int fuse_rename2(struct inode *olddir, struct dentry *oldent, 7741560c974SMiklos Szeredi struct inode *newdir, struct dentry *newent, 7751560c974SMiklos Szeredi unsigned int flags) 7761560c974SMiklos Szeredi { 7771560c974SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(olddir); 7781560c974SMiklos Szeredi int err; 7791560c974SMiklos Szeredi 7801560c974SMiklos Szeredi if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE)) 7811560c974SMiklos Szeredi return -EINVAL; 7821560c974SMiklos Szeredi 7834237ba43SMiklos Szeredi if (flags) { 7841560c974SMiklos Szeredi if (fc->no_rename2 || fc->minor < 23) 7851560c974SMiklos Szeredi return -EINVAL; 7861560c974SMiklos Szeredi 7871560c974SMiklos Szeredi err = fuse_rename_common(olddir, oldent, newdir, newent, flags, 7884237ba43SMiklos Szeredi FUSE_RENAME2, 7894237ba43SMiklos Szeredi sizeof(struct fuse_rename2_in)); 7901560c974SMiklos Szeredi if (err == -ENOSYS) { 7911560c974SMiklos Szeredi fc->no_rename2 = 1; 7921560c974SMiklos Szeredi err = -EINVAL; 7931560c974SMiklos Szeredi } 7944237ba43SMiklos Szeredi } else { 7954237ba43SMiklos Szeredi err = fuse_rename_common(olddir, oldent, newdir, newent, 0, 7964237ba43SMiklos Szeredi FUSE_RENAME, 7974237ba43SMiklos Szeredi sizeof(struct fuse_rename_in)); 7984237ba43SMiklos Szeredi } 7991560c974SMiklos Szeredi 8004237ba43SMiklos Szeredi return err; 8014237ba43SMiklos Szeredi } 8024237ba43SMiklos Szeredi 8039e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir, 8049e6268dbSMiklos Szeredi struct dentry *newent) 8059e6268dbSMiklos Szeredi { 8069e6268dbSMiklos Szeredi int err; 8079e6268dbSMiklos Szeredi struct fuse_link_in inarg; 8082b0143b5SDavid Howells struct inode *inode = d_inode(entry); 8099e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 8107078187aSMiklos Szeredi FUSE_ARGS(args); 8119e6268dbSMiklos Szeredi 8129e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 8139e6268dbSMiklos Szeredi inarg.oldnodeid = get_node_id(inode); 8147078187aSMiklos Szeredi args.in.h.opcode = FUSE_LINK; 8157078187aSMiklos Szeredi args.in.numargs = 2; 8167078187aSMiklos Szeredi args.in.args[0].size = sizeof(inarg); 8177078187aSMiklos Szeredi args.in.args[0].value = &inarg; 8187078187aSMiklos Szeredi args.in.args[1].size = newent->d_name.len + 1; 8197078187aSMiklos Szeredi args.in.args[1].value = newent->d_name.name; 8207078187aSMiklos Szeredi err = create_new_entry(fc, &args, newdir, newent, inode->i_mode); 8219e6268dbSMiklos Szeredi /* Contrary to "normal" filesystems it can happen that link 8229e6268dbSMiklos Szeredi makes two "logical" inodes point to the same "physical" 8239e6268dbSMiklos Szeredi inode. We invalidate the attributes of the old one, so it 8249e6268dbSMiklos Szeredi will reflect changes in the backing inode (link count, 8259e6268dbSMiklos Szeredi etc.) 8269e6268dbSMiklos Szeredi */ 827ac45d613SMiklos Szeredi if (!err) { 828ac45d613SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 829ac45d613SMiklos Szeredi 830ac45d613SMiklos Szeredi spin_lock(&fc->lock); 831ac45d613SMiklos Szeredi fi->attr_version = ++fc->attr_version; 832ac45d613SMiklos Szeredi inc_nlink(inode); 833ac45d613SMiklos Szeredi spin_unlock(&fc->lock); 8349e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 83531f3267bSMaxim Patlasov fuse_update_ctime(inode); 836ac45d613SMiklos Szeredi } else if (err == -EINTR) { 837ac45d613SMiklos Szeredi fuse_invalidate_attr(inode); 838ac45d613SMiklos Szeredi } 8399e6268dbSMiklos Szeredi return err; 8409e6268dbSMiklos Szeredi } 8419e6268dbSMiklos Szeredi 8421fb69e78SMiklos Szeredi static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, 8431fb69e78SMiklos Szeredi struct kstat *stat) 8441fb69e78SMiklos Szeredi { 845203627bbSMiklos Szeredi unsigned int blkbits; 8468373200bSPavel Emelyanov struct fuse_conn *fc = get_fuse_conn(inode); 8478373200bSPavel Emelyanov 8488373200bSPavel Emelyanov /* see the comment in fuse_change_attributes() */ 849b0aa7606SMaxim Patlasov if (fc->writeback_cache && S_ISREG(inode->i_mode)) { 8508373200bSPavel Emelyanov attr->size = i_size_read(inode); 851b0aa7606SMaxim Patlasov attr->mtime = inode->i_mtime.tv_sec; 852b0aa7606SMaxim Patlasov attr->mtimensec = inode->i_mtime.tv_nsec; 85331f3267bSMaxim Patlasov attr->ctime = inode->i_ctime.tv_sec; 85431f3267bSMaxim Patlasov attr->ctimensec = inode->i_ctime.tv_nsec; 855b0aa7606SMaxim Patlasov } 856203627bbSMiklos Szeredi 8571fb69e78SMiklos Szeredi stat->dev = inode->i_sb->s_dev; 8581fb69e78SMiklos Szeredi stat->ino = attr->ino; 8591fb69e78SMiklos Szeredi stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); 8601fb69e78SMiklos Szeredi stat->nlink = attr->nlink; 8618cb08329SEric W. Biederman stat->uid = make_kuid(fc->user_ns, attr->uid); 8628cb08329SEric W. Biederman stat->gid = make_kgid(fc->user_ns, attr->gid); 8631fb69e78SMiklos Szeredi stat->rdev = inode->i_rdev; 8641fb69e78SMiklos Szeredi stat->atime.tv_sec = attr->atime; 8651fb69e78SMiklos Szeredi stat->atime.tv_nsec = attr->atimensec; 8661fb69e78SMiklos Szeredi stat->mtime.tv_sec = attr->mtime; 8671fb69e78SMiklos Szeredi stat->mtime.tv_nsec = attr->mtimensec; 8681fb69e78SMiklos Szeredi stat->ctime.tv_sec = attr->ctime; 8691fb69e78SMiklos Szeredi stat->ctime.tv_nsec = attr->ctimensec; 8701fb69e78SMiklos Szeredi stat->size = attr->size; 8711fb69e78SMiklos Szeredi stat->blocks = attr->blocks; 872203627bbSMiklos Szeredi 873203627bbSMiklos Szeredi if (attr->blksize != 0) 874203627bbSMiklos Szeredi blkbits = ilog2(attr->blksize); 875203627bbSMiklos Szeredi else 876203627bbSMiklos Szeredi blkbits = inode->i_sb->s_blocksize_bits; 877203627bbSMiklos Szeredi 878203627bbSMiklos Szeredi stat->blksize = 1 << blkbits; 8791fb69e78SMiklos Szeredi } 8801fb69e78SMiklos Szeredi 881c79e322fSMiklos Szeredi static int fuse_do_getattr(struct inode *inode, struct kstat *stat, 882c79e322fSMiklos Szeredi struct file *file) 883e5e5558eSMiklos Szeredi { 884e5e5558eSMiklos Szeredi int err; 885c79e322fSMiklos Szeredi struct fuse_getattr_in inarg; 886c79e322fSMiklos Szeredi struct fuse_attr_out outarg; 887e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 8887078187aSMiklos Szeredi FUSE_ARGS(args); 8891fb69e78SMiklos Szeredi u64 attr_version; 8901fb69e78SMiklos Szeredi 8917dca9fd3SMiklos Szeredi attr_version = fuse_get_attr_version(fc); 8921fb69e78SMiklos Szeredi 893c79e322fSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 8940e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 895c79e322fSMiklos Szeredi /* Directories have separate file-handle space */ 896c79e322fSMiklos Szeredi if (file && S_ISREG(inode->i_mode)) { 897c79e322fSMiklos Szeredi struct fuse_file *ff = file->private_data; 898c79e322fSMiklos Szeredi 899c79e322fSMiklos Szeredi inarg.getattr_flags |= FUSE_GETATTR_FH; 900c79e322fSMiklos Szeredi inarg.fh = ff->fh; 901c79e322fSMiklos Szeredi } 9027078187aSMiklos Szeredi args.in.h.opcode = FUSE_GETATTR; 9037078187aSMiklos Szeredi args.in.h.nodeid = get_node_id(inode); 9047078187aSMiklos Szeredi args.in.numargs = 1; 9057078187aSMiklos Szeredi args.in.args[0].size = sizeof(inarg); 9067078187aSMiklos Szeredi args.in.args[0].value = &inarg; 9077078187aSMiklos Szeredi args.out.numargs = 1; 9087078187aSMiklos Szeredi args.out.args[0].size = sizeof(outarg); 9097078187aSMiklos Szeredi args.out.args[0].value = &outarg; 9107078187aSMiklos Szeredi err = fuse_simple_request(fc, &args); 911e5e5558eSMiklos Szeredi if (!err) { 912c79e322fSMiklos Szeredi if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { 913e5e5558eSMiklos Szeredi make_bad_inode(inode); 914e5e5558eSMiklos Szeredi err = -EIO; 915e5e5558eSMiklos Szeredi } else { 916c79e322fSMiklos Szeredi fuse_change_attributes(inode, &outarg.attr, 917c79e322fSMiklos Szeredi attr_timeout(&outarg), 9181fb69e78SMiklos Szeredi attr_version); 9191fb69e78SMiklos Szeredi if (stat) 920c79e322fSMiklos Szeredi fuse_fillattr(inode, &outarg.attr, stat); 921e5e5558eSMiklos Szeredi } 922e5e5558eSMiklos Szeredi } 923e5e5558eSMiklos Szeredi return err; 924e5e5558eSMiklos Szeredi } 925e5e5558eSMiklos Szeredi 9265b97eeacSMiklos Szeredi static int fuse_update_get_attr(struct inode *inode, struct file *file, 927*ff1b89f3SMiklos Szeredi struct kstat *stat, unsigned int flags) 928bcb4be80SMiklos Szeredi { 929bcb4be80SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 9305b97eeacSMiklos Szeredi int err = 0; 931bcb4be80SMiklos Szeredi 932*ff1b89f3SMiklos Szeredi if (!(flags & AT_STATX_DONT_SYNC) && 933*ff1b89f3SMiklos Szeredi time_before64(fi->i_time, get_jiffies_64())) { 93460bcc88aSSeth Forshee forget_all_cached_acls(inode); 935bcb4be80SMiklos Szeredi err = fuse_do_getattr(inode, stat, file); 9365b97eeacSMiklos Szeredi } else if (stat) { 937bcb4be80SMiklos Szeredi generic_fillattr(inode, stat); 938bcb4be80SMiklos Szeredi stat->mode = fi->orig_i_mode; 93945c72cd7SPavel Shilovsky stat->ino = fi->orig_ino; 940bcb4be80SMiklos Szeredi } 941bcb4be80SMiklos Szeredi 942bcb4be80SMiklos Szeredi return err; 943bcb4be80SMiklos Szeredi } 944bcb4be80SMiklos Szeredi 9455b97eeacSMiklos Szeredi int fuse_update_attributes(struct inode *inode, struct file *file) 9465b97eeacSMiklos Szeredi { 947*ff1b89f3SMiklos Szeredi return fuse_update_get_attr(inode, file, NULL, 0); 9485b97eeacSMiklos Szeredi } 9495b97eeacSMiklos Szeredi 9503b463ae0SJohn Muir int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, 951451d0f59SJohn Muir u64 child_nodeid, struct qstr *name) 9523b463ae0SJohn Muir { 9533b463ae0SJohn Muir int err = -ENOTDIR; 9543b463ae0SJohn Muir struct inode *parent; 9553b463ae0SJohn Muir struct dentry *dir; 9563b463ae0SJohn Muir struct dentry *entry; 9573b463ae0SJohn Muir 9583b463ae0SJohn Muir parent = ilookup5(sb, parent_nodeid, fuse_inode_eq, &parent_nodeid); 9593b463ae0SJohn Muir if (!parent) 9603b463ae0SJohn Muir return -ENOENT; 9613b463ae0SJohn Muir 9625955102cSAl Viro inode_lock(parent); 9633b463ae0SJohn Muir if (!S_ISDIR(parent->i_mode)) 9643b463ae0SJohn Muir goto unlock; 9653b463ae0SJohn Muir 9663b463ae0SJohn Muir err = -ENOENT; 9673b463ae0SJohn Muir dir = d_find_alias(parent); 9683b463ae0SJohn Muir if (!dir) 9693b463ae0SJohn Muir goto unlock; 9703b463ae0SJohn Muir 9718387ff25SLinus Torvalds name->hash = full_name_hash(dir, name->name, name->len); 9723b463ae0SJohn Muir entry = d_lookup(dir, name); 9733b463ae0SJohn Muir dput(dir); 9743b463ae0SJohn Muir if (!entry) 9753b463ae0SJohn Muir goto unlock; 9763b463ae0SJohn Muir 9773b463ae0SJohn Muir fuse_invalidate_attr(parent); 9783b463ae0SJohn Muir fuse_invalidate_entry(entry); 979451d0f59SJohn Muir 9802b0143b5SDavid Howells if (child_nodeid != 0 && d_really_is_positive(entry)) { 9815955102cSAl Viro inode_lock(d_inode(entry)); 9822b0143b5SDavid Howells if (get_node_id(d_inode(entry)) != child_nodeid) { 983451d0f59SJohn Muir err = -ENOENT; 984451d0f59SJohn Muir goto badentry; 985451d0f59SJohn Muir } 986451d0f59SJohn Muir if (d_mountpoint(entry)) { 987451d0f59SJohn Muir err = -EBUSY; 988451d0f59SJohn Muir goto badentry; 989451d0f59SJohn Muir } 990e36cb0b8SDavid Howells if (d_is_dir(entry)) { 991451d0f59SJohn Muir shrink_dcache_parent(entry); 992451d0f59SJohn Muir if (!simple_empty(entry)) { 993451d0f59SJohn Muir err = -ENOTEMPTY; 994451d0f59SJohn Muir goto badentry; 995451d0f59SJohn Muir } 9962b0143b5SDavid Howells d_inode(entry)->i_flags |= S_DEAD; 997451d0f59SJohn Muir } 998451d0f59SJohn Muir dont_mount(entry); 9992b0143b5SDavid Howells clear_nlink(d_inode(entry)); 10003b463ae0SJohn Muir err = 0; 1001451d0f59SJohn Muir badentry: 10025955102cSAl Viro inode_unlock(d_inode(entry)); 1003451d0f59SJohn Muir if (!err) 1004451d0f59SJohn Muir d_delete(entry); 1005451d0f59SJohn Muir } else { 1006451d0f59SJohn Muir err = 0; 1007451d0f59SJohn Muir } 1008451d0f59SJohn Muir dput(entry); 10093b463ae0SJohn Muir 10103b463ae0SJohn Muir unlock: 10115955102cSAl Viro inode_unlock(parent); 10123b463ae0SJohn Muir iput(parent); 10133b463ae0SJohn Muir return err; 10143b463ae0SJohn Muir } 10153b463ae0SJohn Muir 101687729a55SMiklos Szeredi /* 101787729a55SMiklos Szeredi * Calling into a user-controlled filesystem gives the filesystem 1018c2132c1bSAnatol Pomozov * daemon ptrace-like capabilities over the current process. This 101987729a55SMiklos Szeredi * means, that the filesystem daemon is able to record the exact 102087729a55SMiklos Szeredi * filesystem operations performed, and can also control the behavior 102187729a55SMiklos Szeredi * of the requester process in otherwise impossible ways. For example 102287729a55SMiklos Szeredi * it can delay the operation for arbitrary length of time allowing 102387729a55SMiklos Szeredi * DoS against the requester. 102487729a55SMiklos Szeredi * 102587729a55SMiklos Szeredi * For this reason only those processes can call into the filesystem, 102687729a55SMiklos Szeredi * for which the owner of the mount has ptrace privilege. This 102787729a55SMiklos Szeredi * excludes processes started by other users, suid or sgid processes. 102887729a55SMiklos Szeredi */ 1029c2132c1bSAnatol Pomozov int fuse_allow_current_process(struct fuse_conn *fc) 103087729a55SMiklos Szeredi { 1031c69e8d9cSDavid Howells const struct cred *cred; 1032c69e8d9cSDavid Howells 103329433a29SMiklos Szeredi if (fc->allow_other) 103473f03c2bSSeth Forshee return current_in_userns(fc->user_ns); 103587729a55SMiklos Szeredi 1036c2132c1bSAnatol Pomozov cred = current_cred(); 1037499dcf20SEric W. Biederman if (uid_eq(cred->euid, fc->user_id) && 1038499dcf20SEric W. Biederman uid_eq(cred->suid, fc->user_id) && 1039499dcf20SEric W. Biederman uid_eq(cred->uid, fc->user_id) && 1040499dcf20SEric W. Biederman gid_eq(cred->egid, fc->group_id) && 1041499dcf20SEric W. Biederman gid_eq(cred->sgid, fc->group_id) && 1042499dcf20SEric W. Biederman gid_eq(cred->gid, fc->group_id)) 1043c2132c1bSAnatol Pomozov return 1; 104487729a55SMiklos Szeredi 1045c2132c1bSAnatol Pomozov return 0; 104687729a55SMiklos Szeredi } 104787729a55SMiklos Szeredi 104831d40d74SMiklos Szeredi static int fuse_access(struct inode *inode, int mask) 104931d40d74SMiklos Szeredi { 105031d40d74SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 10517078187aSMiklos Szeredi FUSE_ARGS(args); 105231d40d74SMiklos Szeredi struct fuse_access_in inarg; 105331d40d74SMiklos Szeredi int err; 105431d40d74SMiklos Szeredi 1055698fa1d1SMiklos Szeredi BUG_ON(mask & MAY_NOT_BLOCK); 1056698fa1d1SMiklos Szeredi 105731d40d74SMiklos Szeredi if (fc->no_access) 105831d40d74SMiklos Szeredi return 0; 105931d40d74SMiklos Szeredi 106031d40d74SMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 1061e6305c43SAl Viro inarg.mask = mask & (MAY_READ | MAY_WRITE | MAY_EXEC); 10627078187aSMiklos Szeredi args.in.h.opcode = FUSE_ACCESS; 10637078187aSMiklos Szeredi args.in.h.nodeid = get_node_id(inode); 10647078187aSMiklos Szeredi args.in.numargs = 1; 10657078187aSMiklos Szeredi args.in.args[0].size = sizeof(inarg); 10667078187aSMiklos Szeredi args.in.args[0].value = &inarg; 10677078187aSMiklos Szeredi err = fuse_simple_request(fc, &args); 106831d40d74SMiklos Szeredi if (err == -ENOSYS) { 106931d40d74SMiklos Szeredi fc->no_access = 1; 107031d40d74SMiklos Szeredi err = 0; 107131d40d74SMiklos Szeredi } 107231d40d74SMiklos Szeredi return err; 107331d40d74SMiklos Szeredi } 107431d40d74SMiklos Szeredi 107510556cb2SAl Viro static int fuse_perm_getattr(struct inode *inode, int mask) 107619690ddbSMiklos Szeredi { 107710556cb2SAl Viro if (mask & MAY_NOT_BLOCK) 107819690ddbSMiklos Szeredi return -ECHILD; 107919690ddbSMiklos Szeredi 108060bcc88aSSeth Forshee forget_all_cached_acls(inode); 108119690ddbSMiklos Szeredi return fuse_do_getattr(inode, NULL, NULL); 108219690ddbSMiklos Szeredi } 108319690ddbSMiklos Szeredi 10846f9f1180SMiklos Szeredi /* 10856f9f1180SMiklos Szeredi * Check permission. The two basic access models of FUSE are: 10866f9f1180SMiklos Szeredi * 10876f9f1180SMiklos Szeredi * 1) Local access checking ('default_permissions' mount option) based 10886f9f1180SMiklos Szeredi * on file mode. This is the plain old disk filesystem permission 10896f9f1180SMiklos Szeredi * modell. 10906f9f1180SMiklos Szeredi * 10916f9f1180SMiklos Szeredi * 2) "Remote" access checking, where server is responsible for 10926f9f1180SMiklos Szeredi * checking permission in each inode operation. An exception to this 10936f9f1180SMiklos Szeredi * is if ->permission() was invoked from sys_access() in which case an 10946f9f1180SMiklos Szeredi * access request is sent. Execute permission is still checked 10956f9f1180SMiklos Szeredi * locally based on file mode. 10966f9f1180SMiklos Szeredi */ 109710556cb2SAl Viro static int fuse_permission(struct inode *inode, int mask) 1098e5e5558eSMiklos Szeredi { 1099e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1100244f6385SMiklos Szeredi bool refreshed = false; 1101244f6385SMiklos Szeredi int err = 0; 1102e5e5558eSMiklos Szeredi 1103c2132c1bSAnatol Pomozov if (!fuse_allow_current_process(fc)) 1104e5e5558eSMiklos Szeredi return -EACCES; 1105244f6385SMiklos Szeredi 1106244f6385SMiklos Szeredi /* 1107e8e96157SMiklos Szeredi * If attributes are needed, refresh them before proceeding 1108244f6385SMiklos Szeredi */ 110929433a29SMiklos Szeredi if (fc->default_permissions || 1110e8e96157SMiklos Szeredi ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { 111119690ddbSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 111219690ddbSMiklos Szeredi 1113126b9d43SMiklos Szeredi if (time_before64(fi->i_time, get_jiffies_64())) { 111419690ddbSMiklos Szeredi refreshed = true; 111519690ddbSMiklos Szeredi 111610556cb2SAl Viro err = fuse_perm_getattr(inode, mask); 1117244f6385SMiklos Szeredi if (err) 1118244f6385SMiklos Szeredi return err; 11191fb69e78SMiklos Szeredi } 112019690ddbSMiklos Szeredi } 1121244f6385SMiklos Szeredi 112229433a29SMiklos Szeredi if (fc->default_permissions) { 11232830ba7fSAl Viro err = generic_permission(inode, mask); 11241e9a4ed9SMiklos Szeredi 11251e9a4ed9SMiklos Szeredi /* If permission is denied, try to refresh file 11261e9a4ed9SMiklos Szeredi attributes. This is also needed, because the root 11271e9a4ed9SMiklos Szeredi node will at first have no permissions */ 1128244f6385SMiklos Szeredi if (err == -EACCES && !refreshed) { 112910556cb2SAl Viro err = fuse_perm_getattr(inode, mask); 11301e9a4ed9SMiklos Szeredi if (!err) 11312830ba7fSAl Viro err = generic_permission(inode, mask); 11321e9a4ed9SMiklos Szeredi } 11331e9a4ed9SMiklos Szeredi 11346f9f1180SMiklos Szeredi /* Note: the opposite of the above test does not 11356f9f1180SMiklos Szeredi exist. So if permissions are revoked this won't be 11366f9f1180SMiklos Szeredi noticed immediately, only after the attribute 11376f9f1180SMiklos Szeredi timeout has expired */ 11389cfcac81SEric Paris } else if (mask & (MAY_ACCESS | MAY_CHDIR)) { 1139e8e96157SMiklos Szeredi err = fuse_access(inode, mask); 1140e8e96157SMiklos Szeredi } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { 1141e8e96157SMiklos Szeredi if (!(inode->i_mode & S_IXUGO)) { 1142e8e96157SMiklos Szeredi if (refreshed) 1143e5e5558eSMiklos Szeredi return -EACCES; 114431d40d74SMiklos Szeredi 114510556cb2SAl Viro err = fuse_perm_getattr(inode, mask); 1146e8e96157SMiklos Szeredi if (!err && !(inode->i_mode & S_IXUGO)) 1147e8e96157SMiklos Szeredi return -EACCES; 1148e8e96157SMiklos Szeredi } 1149e5e5558eSMiklos Szeredi } 1150244f6385SMiklos Szeredi return err; 1151e5e5558eSMiklos Szeredi } 1152e5e5558eSMiklos Szeredi 1153e5e5558eSMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file, 11548d3af7f3SAl Viro struct dir_context *ctx) 1155e5e5558eSMiklos Szeredi { 1156e5e5558eSMiklos Szeredi while (nbytes >= FUSE_NAME_OFFSET) { 1157e5e5558eSMiklos Szeredi struct fuse_dirent *dirent = (struct fuse_dirent *) buf; 1158e5e5558eSMiklos Szeredi size_t reclen = FUSE_DIRENT_SIZE(dirent); 1159e5e5558eSMiklos Szeredi if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) 1160e5e5558eSMiklos Szeredi return -EIO; 1161e5e5558eSMiklos Szeredi if (reclen > nbytes) 1162e5e5558eSMiklos Szeredi break; 1163efeb9e60SMiklos Szeredi if (memchr(dirent->name, '/', dirent->namelen) != NULL) 1164efeb9e60SMiklos Szeredi return -EIO; 1165e5e5558eSMiklos Szeredi 11668d3af7f3SAl Viro if (!dir_emit(ctx, dirent->name, dirent->namelen, 11678d3af7f3SAl Viro dirent->ino, dirent->type)) 1168e5e5558eSMiklos Szeredi break; 1169e5e5558eSMiklos Szeredi 1170e5e5558eSMiklos Szeredi buf += reclen; 1171e5e5558eSMiklos Szeredi nbytes -= reclen; 11728d3af7f3SAl Viro ctx->pos = dirent->off; 1173e5e5558eSMiklos Szeredi } 1174e5e5558eSMiklos Szeredi 1175e5e5558eSMiklos Szeredi return 0; 1176e5e5558eSMiklos Szeredi } 1177e5e5558eSMiklos Szeredi 11780b05b183SAnand V. Avati static int fuse_direntplus_link(struct file *file, 11790b05b183SAnand V. Avati struct fuse_direntplus *direntplus, 11800b05b183SAnand V. Avati u64 attr_version) 11810b05b183SAnand V. Avati { 11820b05b183SAnand V. Avati struct fuse_entry_out *o = &direntplus->entry_out; 11830b05b183SAnand V. Avati struct fuse_dirent *dirent = &direntplus->dirent; 11840b05b183SAnand V. Avati struct dentry *parent = file->f_path.dentry; 11850b05b183SAnand V. Avati struct qstr name = QSTR_INIT(dirent->name, dirent->namelen); 11860b05b183SAnand V. Avati struct dentry *dentry; 11870b05b183SAnand V. Avati struct dentry *alias; 11882b0143b5SDavid Howells struct inode *dir = d_inode(parent); 11890b05b183SAnand V. Avati struct fuse_conn *fc; 11900b05b183SAnand V. Avati struct inode *inode; 1191d9b3dbdcSAl Viro DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); 11920b05b183SAnand V. Avati 11930b05b183SAnand V. Avati if (!o->nodeid) { 11940b05b183SAnand V. Avati /* 11950b05b183SAnand V. Avati * Unlike in the case of fuse_lookup, zero nodeid does not mean 11960b05b183SAnand V. Avati * ENOENT. Instead, it only means the userspace filesystem did 11970b05b183SAnand V. Avati * not want to return attributes/handle for this entry. 11980b05b183SAnand V. Avati * 11990b05b183SAnand V. Avati * So do nothing. 12000b05b183SAnand V. Avati */ 12010b05b183SAnand V. Avati return 0; 12020b05b183SAnand V. Avati } 12030b05b183SAnand V. Avati 12040b05b183SAnand V. Avati if (name.name[0] == '.') { 12050b05b183SAnand V. Avati /* 12060b05b183SAnand V. Avati * We could potentially refresh the attributes of the directory 12070b05b183SAnand V. Avati * and its parent? 12080b05b183SAnand V. Avati */ 12090b05b183SAnand V. Avati if (name.len == 1) 12100b05b183SAnand V. Avati return 0; 12110b05b183SAnand V. Avati if (name.name[1] == '.' && name.len == 2) 12120b05b183SAnand V. Avati return 0; 12130b05b183SAnand V. Avati } 1214a28ef45cSMiklos Szeredi 1215a28ef45cSMiklos Szeredi if (invalid_nodeid(o->nodeid)) 1216a28ef45cSMiklos Szeredi return -EIO; 1217a28ef45cSMiklos Szeredi if (!fuse_valid_type(o->attr.mode)) 1218a28ef45cSMiklos Szeredi return -EIO; 1219a28ef45cSMiklos Szeredi 12200b05b183SAnand V. Avati fc = get_fuse_conn(dir); 12210b05b183SAnand V. Avati 12228387ff25SLinus Torvalds name.hash = full_name_hash(parent, name.name, name.len); 12230b05b183SAnand V. Avati dentry = d_lookup(parent, &name); 1224d9b3dbdcSAl Viro if (!dentry) { 1225d9b3dbdcSAl Viro retry: 1226d9b3dbdcSAl Viro dentry = d_alloc_parallel(parent, &name, &wq); 1227d9b3dbdcSAl Viro if (IS_ERR(dentry)) 1228d9b3dbdcSAl Viro return PTR_ERR(dentry); 1229d9b3dbdcSAl Viro } 1230d9b3dbdcSAl Viro if (!d_in_lookup(dentry)) { 1231d9b3dbdcSAl Viro struct fuse_inode *fi; 12322b0143b5SDavid Howells inode = d_inode(dentry); 1233d9b3dbdcSAl Viro if (!inode || 1234d9b3dbdcSAl Viro get_node_id(inode) != o->nodeid || 1235a28ef45cSMiklos Szeredi ((o->attr.mode ^ inode->i_mode) & S_IFMT)) { 12365542aa2fSEric W. Biederman d_invalidate(dentry); 1237d9b3dbdcSAl Viro dput(dentry); 1238d9b3dbdcSAl Viro goto retry; 1239d9b3dbdcSAl Viro } 1240d9b3dbdcSAl Viro if (is_bad_inode(inode)) { 1241d9b3dbdcSAl Viro dput(dentry); 1242d9b3dbdcSAl Viro return -EIO; 1243d9b3dbdcSAl Viro } 1244d9b3dbdcSAl Viro 12450b05b183SAnand V. Avati fi = get_fuse_inode(inode); 12460b05b183SAnand V. Avati spin_lock(&fc->lock); 12470b05b183SAnand V. Avati fi->nlookup++; 12480b05b183SAnand V. Avati spin_unlock(&fc->lock); 12490b05b183SAnand V. Avati 125060bcc88aSSeth Forshee forget_all_cached_acls(inode); 1251fa2b7213SMiklos Szeredi fuse_change_attributes(inode, &o->attr, 1252fa2b7213SMiklos Szeredi entry_attr_timeout(o), 1253fa2b7213SMiklos Szeredi attr_version); 12540b05b183SAnand V. Avati /* 1255d9b3dbdcSAl Viro * The other branch comes via fuse_iget() 12560b05b183SAnand V. Avati * which bumps nlookup inside 12570b05b183SAnand V. Avati */ 1258d9b3dbdcSAl Viro } else { 12590b05b183SAnand V. Avati inode = fuse_iget(dir->i_sb, o->nodeid, o->generation, 1260d9b3dbdcSAl Viro &o->attr, entry_attr_timeout(o), 1261d9b3dbdcSAl Viro attr_version); 12620b05b183SAnand V. Avati if (!inode) 1263d9b3dbdcSAl Viro inode = ERR_PTR(-ENOMEM); 12640b05b183SAnand V. Avati 126541d28bcaSAl Viro alias = d_splice_alias(inode, dentry); 1266d9b3dbdcSAl Viro d_lookup_done(dentry); 12670b05b183SAnand V. Avati if (alias) { 12680b05b183SAnand V. Avati dput(dentry); 12690b05b183SAnand V. Avati dentry = alias; 12700b05b183SAnand V. Avati } 1271d9b3dbdcSAl Viro if (IS_ERR(dentry)) 1272d9b3dbdcSAl Viro return PTR_ERR(dentry); 1273d9b3dbdcSAl Viro } 12746314efeeSMiklos Szeredi if (fc->readdirplus_auto) 12756314efeeSMiklos Szeredi set_bit(FUSE_I_INIT_RDPLUS, &get_fuse_inode(inode)->state); 12760b05b183SAnand V. Avati fuse_change_entry_timeout(dentry, o); 12770b05b183SAnand V. Avati 12780b05b183SAnand V. Avati dput(dentry); 1279d9b3dbdcSAl Viro return 0; 12800b05b183SAnand V. Avati } 12810b05b183SAnand V. Avati 12820b05b183SAnand V. Avati static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file, 12838d3af7f3SAl Viro struct dir_context *ctx, u64 attr_version) 12840b05b183SAnand V. Avati { 12850b05b183SAnand V. Avati struct fuse_direntplus *direntplus; 12860b05b183SAnand V. Avati struct fuse_dirent *dirent; 12870b05b183SAnand V. Avati size_t reclen; 12880b05b183SAnand V. Avati int over = 0; 12890b05b183SAnand V. Avati int ret; 12900b05b183SAnand V. Avati 12910b05b183SAnand V. Avati while (nbytes >= FUSE_NAME_OFFSET_DIRENTPLUS) { 12920b05b183SAnand V. Avati direntplus = (struct fuse_direntplus *) buf; 12930b05b183SAnand V. Avati dirent = &direntplus->dirent; 12940b05b183SAnand V. Avati reclen = FUSE_DIRENTPLUS_SIZE(direntplus); 12950b05b183SAnand V. Avati 12960b05b183SAnand V. Avati if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) 12970b05b183SAnand V. Avati return -EIO; 12980b05b183SAnand V. Avati if (reclen > nbytes) 12990b05b183SAnand V. Avati break; 1300efeb9e60SMiklos Szeredi if (memchr(dirent->name, '/', dirent->namelen) != NULL) 1301efeb9e60SMiklos Szeredi return -EIO; 13020b05b183SAnand V. Avati 13030b05b183SAnand V. Avati if (!over) { 13040b05b183SAnand V. Avati /* We fill entries into dstbuf only as much as 13050b05b183SAnand V. Avati it can hold. But we still continue iterating 13060b05b183SAnand V. Avati over remaining entries to link them. If not, 13070b05b183SAnand V. Avati we need to send a FORGET for each of those 13080b05b183SAnand V. Avati which we did not link. 13090b05b183SAnand V. Avati */ 13108d3af7f3SAl Viro over = !dir_emit(ctx, dirent->name, dirent->namelen, 13118d3af7f3SAl Viro dirent->ino, dirent->type); 1312c6cdd514SMiklos Szeredi if (!over) 13138d3af7f3SAl Viro ctx->pos = dirent->off; 13140b05b183SAnand V. Avati } 13150b05b183SAnand V. Avati 13160b05b183SAnand V. Avati buf += reclen; 13170b05b183SAnand V. Avati nbytes -= reclen; 13180b05b183SAnand V. Avati 13190b05b183SAnand V. Avati ret = fuse_direntplus_link(file, direntplus, attr_version); 13200b05b183SAnand V. Avati if (ret) 13210b05b183SAnand V. Avati fuse_force_forget(file, direntplus->entry_out.nodeid); 13220b05b183SAnand V. Avati } 13230b05b183SAnand V. Avati 13240b05b183SAnand V. Avati return 0; 13250b05b183SAnand V. Avati } 13260b05b183SAnand V. Avati 13278d3af7f3SAl Viro static int fuse_readdir(struct file *file, struct dir_context *ctx) 1328e5e5558eSMiklos Szeredi { 13294582a4abSFeng Shuo int plus, err; 133004730fefSMiklos Szeredi size_t nbytes; 133104730fefSMiklos Szeredi struct page *page; 1332496ad9aaSAl Viro struct inode *inode = file_inode(file); 133304730fefSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1334248d86e8SMiklos Szeredi struct fuse_req *req; 13350b05b183SAnand V. Avati u64 attr_version = 0; 1336248d86e8SMiklos Szeredi 1337248d86e8SMiklos Szeredi if (is_bad_inode(inode)) 1338248d86e8SMiklos Szeredi return -EIO; 1339248d86e8SMiklos Szeredi 1340b111c8c0SMaxim Patlasov req = fuse_get_req(fc, 1); 1341ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1342ce1d5a49SMiklos Szeredi return PTR_ERR(req); 1343e5e5558eSMiklos Szeredi 134404730fefSMiklos Szeredi page = alloc_page(GFP_KERNEL); 134504730fefSMiklos Szeredi if (!page) { 134604730fefSMiklos Szeredi fuse_put_request(fc, req); 1347e5e5558eSMiklos Szeredi return -ENOMEM; 134804730fefSMiklos Szeredi } 13494582a4abSFeng Shuo 13508d3af7f3SAl Viro plus = fuse_use_readdirplus(inode, ctx); 1351f4975c67SMiklos Szeredi req->out.argpages = 1; 135204730fefSMiklos Szeredi req->num_pages = 1; 135304730fefSMiklos Szeredi req->pages[0] = page; 135485f40aecSMaxim Patlasov req->page_descs[0].length = PAGE_SIZE; 13554582a4abSFeng Shuo if (plus) { 13560b05b183SAnand V. Avati attr_version = fuse_get_attr_version(fc); 13578d3af7f3SAl Viro fuse_read_fill(req, file, ctx->pos, PAGE_SIZE, 13580b05b183SAnand V. Avati FUSE_READDIRPLUS); 13590b05b183SAnand V. Avati } else { 13608d3af7f3SAl Viro fuse_read_fill(req, file, ctx->pos, PAGE_SIZE, 13610b05b183SAnand V. Avati FUSE_READDIR); 13620b05b183SAnand V. Avati } 13635c672ab3SMiklos Szeredi fuse_lock_inode(inode); 1364b93f858aSTejun Heo fuse_request_send(fc, req); 13655c672ab3SMiklos Szeredi fuse_unlock_inode(inode); 1366361b1eb5SMiklos Szeredi nbytes = req->out.args[0].size; 136704730fefSMiklos Szeredi err = req->out.h.error; 136804730fefSMiklos Szeredi fuse_put_request(fc, req); 13690b05b183SAnand V. Avati if (!err) { 13704582a4abSFeng Shuo if (plus) { 13710b05b183SAnand V. Avati err = parse_dirplusfile(page_address(page), nbytes, 13728d3af7f3SAl Viro file, ctx, 13730b05b183SAnand V. Avati attr_version); 13740b05b183SAnand V. Avati } else { 13750b05b183SAnand V. Avati err = parse_dirfile(page_address(page), nbytes, file, 13768d3af7f3SAl Viro ctx); 13770b05b183SAnand V. Avati } 13780b05b183SAnand V. Avati } 1379e5e5558eSMiklos Szeredi 138004730fefSMiklos Szeredi __free_page(page); 1381451418fcSAndrew Gallagher fuse_invalidate_atime(inode); 138204730fefSMiklos Szeredi return err; 1383e5e5558eSMiklos Szeredi } 1384e5e5558eSMiklos Szeredi 13856b255391SAl Viro static const char *fuse_get_link(struct dentry *dentry, 1386fceef393SAl Viro struct inode *inode, 1387fceef393SAl Viro struct delayed_call *done) 1388e5e5558eSMiklos Szeredi { 1389e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 13907078187aSMiklos Szeredi FUSE_ARGS(args); 1391e5e5558eSMiklos Szeredi char *link; 13927078187aSMiklos Szeredi ssize_t ret; 1393e5e5558eSMiklos Szeredi 13946b255391SAl Viro if (!dentry) 13956b255391SAl Viro return ERR_PTR(-ECHILD); 13966b255391SAl Viro 1397cd3417c8SAl Viro link = kmalloc(PAGE_SIZE, GFP_KERNEL); 13987078187aSMiklos Szeredi if (!link) 13997078187aSMiklos Szeredi return ERR_PTR(-ENOMEM); 14007078187aSMiklos Szeredi 14017078187aSMiklos Szeredi args.in.h.opcode = FUSE_READLINK; 14027078187aSMiklos Szeredi args.in.h.nodeid = get_node_id(inode); 14037078187aSMiklos Szeredi args.out.argvar = 1; 14047078187aSMiklos Szeredi args.out.numargs = 1; 14057078187aSMiklos Szeredi args.out.args[0].size = PAGE_SIZE - 1; 14067078187aSMiklos Szeredi args.out.args[0].value = link; 14077078187aSMiklos Szeredi ret = fuse_simple_request(fc, &args); 14087078187aSMiklos Szeredi if (ret < 0) { 1409cd3417c8SAl Viro kfree(link); 14107078187aSMiklos Szeredi link = ERR_PTR(ret); 14117078187aSMiklos Szeredi } else { 14127078187aSMiklos Szeredi link[ret] = '\0'; 1413fceef393SAl Viro set_delayed_call(done, kfree_link, link); 14147078187aSMiklos Szeredi } 1415451418fcSAndrew Gallagher fuse_invalidate_atime(inode); 1416e5e5558eSMiklos Szeredi return link; 1417e5e5558eSMiklos Szeredi } 1418e5e5558eSMiklos Szeredi 1419e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file) 1420e5e5558eSMiklos Szeredi { 142191fe96b4SMiklos Szeredi return fuse_open_common(inode, file, true); 1422e5e5558eSMiklos Szeredi } 1423e5e5558eSMiklos Szeredi 1424e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file) 1425e5e5558eSMiklos Szeredi { 14268b0797a4SMiklos Szeredi fuse_release_common(file, FUSE_RELEASEDIR); 14278b0797a4SMiklos Szeredi 14288b0797a4SMiklos Szeredi return 0; 1429e5e5558eSMiklos Szeredi } 1430e5e5558eSMiklos Szeredi 143102c24a82SJosef Bacik static int fuse_dir_fsync(struct file *file, loff_t start, loff_t end, 143202c24a82SJosef Bacik int datasync) 143382547981SMiklos Szeredi { 143402c24a82SJosef Bacik return fuse_fsync_common(file, start, end, datasync, 1); 143582547981SMiklos Szeredi } 143682547981SMiklos Szeredi 1437b18da0c5SMiklos Szeredi static long fuse_dir_ioctl(struct file *file, unsigned int cmd, 1438b18da0c5SMiklos Szeredi unsigned long arg) 1439b18da0c5SMiklos Szeredi { 1440b18da0c5SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(file->f_mapping->host); 1441b18da0c5SMiklos Szeredi 1442b18da0c5SMiklos Szeredi /* FUSE_IOCTL_DIR only supported for API version >= 7.18 */ 1443b18da0c5SMiklos Szeredi if (fc->minor < 18) 1444b18da0c5SMiklos Szeredi return -ENOTTY; 1445b18da0c5SMiklos Szeredi 1446b18da0c5SMiklos Szeredi return fuse_ioctl_common(file, cmd, arg, FUSE_IOCTL_DIR); 1447b18da0c5SMiklos Szeredi } 1448b18da0c5SMiklos Szeredi 1449b18da0c5SMiklos Szeredi static long fuse_dir_compat_ioctl(struct file *file, unsigned int cmd, 1450b18da0c5SMiklos Szeredi unsigned long arg) 1451b18da0c5SMiklos Szeredi { 1452b18da0c5SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(file->f_mapping->host); 1453b18da0c5SMiklos Szeredi 1454b18da0c5SMiklos Szeredi if (fc->minor < 18) 1455b18da0c5SMiklos Szeredi return -ENOTTY; 1456b18da0c5SMiklos Szeredi 1457b18da0c5SMiklos Szeredi return fuse_ioctl_common(file, cmd, arg, 1458b18da0c5SMiklos Szeredi FUSE_IOCTL_COMPAT | FUSE_IOCTL_DIR); 1459b18da0c5SMiklos Szeredi } 1460b18da0c5SMiklos Szeredi 1461b0aa7606SMaxim Patlasov static bool update_mtime(unsigned ivalid, bool trust_local_mtime) 146217637cbaSMiklos Szeredi { 146317637cbaSMiklos Szeredi /* Always update if mtime is explicitly set */ 146417637cbaSMiklos Szeredi if (ivalid & ATTR_MTIME_SET) 146517637cbaSMiklos Szeredi return true; 146617637cbaSMiklos Szeredi 1467b0aa7606SMaxim Patlasov /* Or if kernel i_mtime is the official one */ 1468b0aa7606SMaxim Patlasov if (trust_local_mtime) 1469b0aa7606SMaxim Patlasov return true; 1470b0aa7606SMaxim Patlasov 147117637cbaSMiklos Szeredi /* If it's an open(O_TRUNC) or an ftruncate(), don't update */ 147217637cbaSMiklos Szeredi if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE))) 147317637cbaSMiklos Szeredi return false; 147417637cbaSMiklos Szeredi 147517637cbaSMiklos Szeredi /* In all other cases update */ 147617637cbaSMiklos Szeredi return true; 147717637cbaSMiklos Szeredi } 147817637cbaSMiklos Szeredi 14798cb08329SEric W. Biederman static void iattr_to_fattr(struct fuse_conn *fc, struct iattr *iattr, 14808cb08329SEric W. Biederman struct fuse_setattr_in *arg, bool trust_local_cmtime) 14819e6268dbSMiklos Szeredi { 14829e6268dbSMiklos Szeredi unsigned ivalid = iattr->ia_valid; 14839e6268dbSMiklos Szeredi 14849e6268dbSMiklos Szeredi if (ivalid & ATTR_MODE) 1485befc649cSMiklos Szeredi arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode; 14869e6268dbSMiklos Szeredi if (ivalid & ATTR_UID) 14878cb08329SEric W. Biederman arg->valid |= FATTR_UID, arg->uid = from_kuid(fc->user_ns, iattr->ia_uid); 14889e6268dbSMiklos Szeredi if (ivalid & ATTR_GID) 14898cb08329SEric W. Biederman arg->valid |= FATTR_GID, arg->gid = from_kgid(fc->user_ns, iattr->ia_gid); 14909e6268dbSMiklos Szeredi if (ivalid & ATTR_SIZE) 1491befc649cSMiklos Szeredi arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size; 149217637cbaSMiklos Szeredi if (ivalid & ATTR_ATIME) { 149317637cbaSMiklos Szeredi arg->valid |= FATTR_ATIME; 1494befc649cSMiklos Szeredi arg->atime = iattr->ia_atime.tv_sec; 149517637cbaSMiklos Szeredi arg->atimensec = iattr->ia_atime.tv_nsec; 149617637cbaSMiklos Szeredi if (!(ivalid & ATTR_ATIME_SET)) 149717637cbaSMiklos Szeredi arg->valid |= FATTR_ATIME_NOW; 149817637cbaSMiklos Szeredi } 14993ad22c62SMaxim Patlasov if ((ivalid & ATTR_MTIME) && update_mtime(ivalid, trust_local_cmtime)) { 150017637cbaSMiklos Szeredi arg->valid |= FATTR_MTIME; 1501befc649cSMiklos Szeredi arg->mtime = iattr->ia_mtime.tv_sec; 150217637cbaSMiklos Szeredi arg->mtimensec = iattr->ia_mtime.tv_nsec; 15033ad22c62SMaxim Patlasov if (!(ivalid & ATTR_MTIME_SET) && !trust_local_cmtime) 150417637cbaSMiklos Szeredi arg->valid |= FATTR_MTIME_NOW; 15059e6268dbSMiklos Szeredi } 15063ad22c62SMaxim Patlasov if ((ivalid & ATTR_CTIME) && trust_local_cmtime) { 15073ad22c62SMaxim Patlasov arg->valid |= FATTR_CTIME; 15083ad22c62SMaxim Patlasov arg->ctime = iattr->ia_ctime.tv_sec; 15093ad22c62SMaxim Patlasov arg->ctimensec = iattr->ia_ctime.tv_nsec; 15103ad22c62SMaxim Patlasov } 15119e6268dbSMiklos Szeredi } 15129e6268dbSMiklos Szeredi 15136f9f1180SMiklos Szeredi /* 15143be5a52bSMiklos Szeredi * Prevent concurrent writepages on inode 15153be5a52bSMiklos Szeredi * 15163be5a52bSMiklos Szeredi * This is done by adding a negative bias to the inode write counter 15173be5a52bSMiklos Szeredi * and waiting for all pending writes to finish. 15183be5a52bSMiklos Szeredi */ 15193be5a52bSMiklos Szeredi void fuse_set_nowrite(struct inode *inode) 15203be5a52bSMiklos Szeredi { 15213be5a52bSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 15223be5a52bSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 15233be5a52bSMiklos Szeredi 15245955102cSAl Viro BUG_ON(!inode_is_locked(inode)); 15253be5a52bSMiklos Szeredi 15263be5a52bSMiklos Szeredi spin_lock(&fc->lock); 15273be5a52bSMiklos Szeredi BUG_ON(fi->writectr < 0); 15283be5a52bSMiklos Szeredi fi->writectr += FUSE_NOWRITE; 15293be5a52bSMiklos Szeredi spin_unlock(&fc->lock); 15303be5a52bSMiklos Szeredi wait_event(fi->page_waitq, fi->writectr == FUSE_NOWRITE); 15313be5a52bSMiklos Szeredi } 15323be5a52bSMiklos Szeredi 15333be5a52bSMiklos Szeredi /* 15343be5a52bSMiklos Szeredi * Allow writepages on inode 15353be5a52bSMiklos Szeredi * 15363be5a52bSMiklos Szeredi * Remove the bias from the writecounter and send any queued 15373be5a52bSMiklos Szeredi * writepages. 15383be5a52bSMiklos Szeredi */ 15393be5a52bSMiklos Szeredi static void __fuse_release_nowrite(struct inode *inode) 15403be5a52bSMiklos Szeredi { 15413be5a52bSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 15423be5a52bSMiklos Szeredi 15433be5a52bSMiklos Szeredi BUG_ON(fi->writectr != FUSE_NOWRITE); 15443be5a52bSMiklos Szeredi fi->writectr = 0; 15453be5a52bSMiklos Szeredi fuse_flush_writepages(inode); 15463be5a52bSMiklos Szeredi } 15473be5a52bSMiklos Szeredi 15483be5a52bSMiklos Szeredi void fuse_release_nowrite(struct inode *inode) 15493be5a52bSMiklos Szeredi { 15503be5a52bSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 15513be5a52bSMiklos Szeredi 15523be5a52bSMiklos Szeredi spin_lock(&fc->lock); 15533be5a52bSMiklos Szeredi __fuse_release_nowrite(inode); 15543be5a52bSMiklos Szeredi spin_unlock(&fc->lock); 15553be5a52bSMiklos Szeredi } 15563be5a52bSMiklos Szeredi 15577078187aSMiklos Szeredi static void fuse_setattr_fill(struct fuse_conn *fc, struct fuse_args *args, 1558b0aa7606SMaxim Patlasov struct inode *inode, 1559b0aa7606SMaxim Patlasov struct fuse_setattr_in *inarg_p, 1560b0aa7606SMaxim Patlasov struct fuse_attr_out *outarg_p) 1561b0aa7606SMaxim Patlasov { 15627078187aSMiklos Szeredi args->in.h.opcode = FUSE_SETATTR; 15637078187aSMiklos Szeredi args->in.h.nodeid = get_node_id(inode); 15647078187aSMiklos Szeredi args->in.numargs = 1; 15657078187aSMiklos Szeredi args->in.args[0].size = sizeof(*inarg_p); 15667078187aSMiklos Szeredi args->in.args[0].value = inarg_p; 15677078187aSMiklos Szeredi args->out.numargs = 1; 15687078187aSMiklos Szeredi args->out.args[0].size = sizeof(*outarg_p); 15697078187aSMiklos Szeredi args->out.args[0].value = outarg_p; 1570b0aa7606SMaxim Patlasov } 1571b0aa7606SMaxim Patlasov 1572b0aa7606SMaxim Patlasov /* 1573b0aa7606SMaxim Patlasov * Flush inode->i_mtime to the server 1574b0aa7606SMaxim Patlasov */ 1575ab9e13f7SMaxim Patlasov int fuse_flush_times(struct inode *inode, struct fuse_file *ff) 1576b0aa7606SMaxim Patlasov { 1577b0aa7606SMaxim Patlasov struct fuse_conn *fc = get_fuse_conn(inode); 15787078187aSMiklos Szeredi FUSE_ARGS(args); 1579b0aa7606SMaxim Patlasov struct fuse_setattr_in inarg; 1580b0aa7606SMaxim Patlasov struct fuse_attr_out outarg; 1581b0aa7606SMaxim Patlasov 1582b0aa7606SMaxim Patlasov memset(&inarg, 0, sizeof(inarg)); 1583b0aa7606SMaxim Patlasov memset(&outarg, 0, sizeof(outarg)); 1584b0aa7606SMaxim Patlasov 1585ab9e13f7SMaxim Patlasov inarg.valid = FATTR_MTIME; 1586b0aa7606SMaxim Patlasov inarg.mtime = inode->i_mtime.tv_sec; 1587b0aa7606SMaxim Patlasov inarg.mtimensec = inode->i_mtime.tv_nsec; 1588ab9e13f7SMaxim Patlasov if (fc->minor >= 23) { 1589ab9e13f7SMaxim Patlasov inarg.valid |= FATTR_CTIME; 1590ab9e13f7SMaxim Patlasov inarg.ctime = inode->i_ctime.tv_sec; 1591ab9e13f7SMaxim Patlasov inarg.ctimensec = inode->i_ctime.tv_nsec; 1592ab9e13f7SMaxim Patlasov } 15931e18bda8SMiklos Szeredi if (ff) { 15941e18bda8SMiklos Szeredi inarg.valid |= FATTR_FH; 15951e18bda8SMiklos Szeredi inarg.fh = ff->fh; 15961e18bda8SMiklos Szeredi } 15977078187aSMiklos Szeredi fuse_setattr_fill(fc, &args, inode, &inarg, &outarg); 1598b0aa7606SMaxim Patlasov 15997078187aSMiklos Szeredi return fuse_simple_request(fc, &args); 1600b0aa7606SMaxim Patlasov } 1601b0aa7606SMaxim Patlasov 16023be5a52bSMiklos Szeredi /* 16036f9f1180SMiklos Szeredi * Set attributes, and at the same time refresh them. 16046f9f1180SMiklos Szeredi * 16056f9f1180SMiklos Szeredi * Truncation is slightly complicated, because the 'truncate' request 16066f9f1180SMiklos Szeredi * may fail, in which case we don't want to touch the mapping. 16079ffbb916SMiklos Szeredi * vmtruncate() doesn't allow for this case, so do the rlimit checking 16089ffbb916SMiklos Szeredi * and the actual truncation by hand. 16096f9f1180SMiklos Szeredi */ 161062490330SJan Kara int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, 161149d4914fSMiklos Szeredi struct file *file) 16129e6268dbSMiklos Szeredi { 161362490330SJan Kara struct inode *inode = d_inode(dentry); 16149e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 161506a7c3c2SMaxim Patlasov struct fuse_inode *fi = get_fuse_inode(inode); 16167078187aSMiklos Szeredi FUSE_ARGS(args); 16179e6268dbSMiklos Szeredi struct fuse_setattr_in inarg; 16189e6268dbSMiklos Szeredi struct fuse_attr_out outarg; 16193be5a52bSMiklos Szeredi bool is_truncate = false; 16208373200bSPavel Emelyanov bool is_wb = fc->writeback_cache; 16213be5a52bSMiklos Szeredi loff_t oldsize; 16229e6268dbSMiklos Szeredi int err; 16233ad22c62SMaxim Patlasov bool trust_local_cmtime = is_wb && S_ISREG(inode->i_mode); 16249e6268dbSMiklos Szeredi 162529433a29SMiklos Szeredi if (!fc->default_permissions) 1626db78b877SChristoph Hellwig attr->ia_valid |= ATTR_FORCE; 1627db78b877SChristoph Hellwig 162831051c85SJan Kara err = setattr_prepare(dentry, attr); 16291e9a4ed9SMiklos Szeredi if (err) 16301e9a4ed9SMiklos Szeredi return err; 16311e9a4ed9SMiklos Szeredi 16328d56adddSMiklos Szeredi if (attr->ia_valid & ATTR_OPEN) { 1633df0e91d4SMiklos Szeredi /* This is coming from open(..., ... | O_TRUNC); */ 1634df0e91d4SMiklos Szeredi WARN_ON(!(attr->ia_valid & ATTR_SIZE)); 1635df0e91d4SMiklos Szeredi WARN_ON(attr->ia_size != 0); 1636df0e91d4SMiklos Szeredi if (fc->atomic_o_trunc) { 1637df0e91d4SMiklos Szeredi /* 1638df0e91d4SMiklos Szeredi * No need to send request to userspace, since actual 1639df0e91d4SMiklos Szeredi * truncation has already been done by OPEN. But still 1640df0e91d4SMiklos Szeredi * need to truncate page cache. 1641df0e91d4SMiklos Szeredi */ 1642df0e91d4SMiklos Szeredi i_size_write(inode, 0); 1643df0e91d4SMiklos Szeredi truncate_pagecache(inode, 0); 16446ff958edSMiklos Szeredi return 0; 1645df0e91d4SMiklos Szeredi } 16468d56adddSMiklos Szeredi file = NULL; 16478d56adddSMiklos Szeredi } 16486ff958edSMiklos Szeredi 16492c27c65eSChristoph Hellwig if (attr->ia_valid & ATTR_SIZE) 16503be5a52bSMiklos Szeredi is_truncate = true; 16519e6268dbSMiklos Szeredi 165206a7c3c2SMaxim Patlasov if (is_truncate) { 16533be5a52bSMiklos Szeredi fuse_set_nowrite(inode); 165406a7c3c2SMaxim Patlasov set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); 16553ad22c62SMaxim Patlasov if (trust_local_cmtime && attr->ia_size != inode->i_size) 16563ad22c62SMaxim Patlasov attr->ia_valid |= ATTR_MTIME | ATTR_CTIME; 165706a7c3c2SMaxim Patlasov } 16583be5a52bSMiklos Szeredi 16599e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 16600e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 16618cb08329SEric W. Biederman iattr_to_fattr(fc, attr, &inarg, trust_local_cmtime); 166249d4914fSMiklos Szeredi if (file) { 166349d4914fSMiklos Szeredi struct fuse_file *ff = file->private_data; 166449d4914fSMiklos Szeredi inarg.valid |= FATTR_FH; 166549d4914fSMiklos Szeredi inarg.fh = ff->fh; 166649d4914fSMiklos Szeredi } 1667f3332114SMiklos Szeredi if (attr->ia_valid & ATTR_SIZE) { 1668f3332114SMiklos Szeredi /* For mandatory locking in truncate */ 1669f3332114SMiklos Szeredi inarg.valid |= FATTR_LOCKOWNER; 1670f3332114SMiklos Szeredi inarg.lock_owner = fuse_lock_owner_id(fc, current->files); 1671f3332114SMiklos Szeredi } 16727078187aSMiklos Szeredi fuse_setattr_fill(fc, &args, inode, &inarg, &outarg); 16737078187aSMiklos Szeredi err = fuse_simple_request(fc, &args); 1674e00d2c2dSMiklos Szeredi if (err) { 1675e00d2c2dSMiklos Szeredi if (err == -EINTR) 1676e00d2c2dSMiklos Szeredi fuse_invalidate_attr(inode); 16773be5a52bSMiklos Szeredi goto error; 1678e00d2c2dSMiklos Szeredi } 1679e00d2c2dSMiklos Szeredi 16809e6268dbSMiklos Szeredi if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { 16819e6268dbSMiklos Szeredi make_bad_inode(inode); 16823be5a52bSMiklos Szeredi err = -EIO; 16833be5a52bSMiklos Szeredi goto error; 16849e6268dbSMiklos Szeredi } 16859e6268dbSMiklos Szeredi 16863be5a52bSMiklos Szeredi spin_lock(&fc->lock); 1687b0aa7606SMaxim Patlasov /* the kernel maintains i_mtime locally */ 16883ad22c62SMaxim Patlasov if (trust_local_cmtime) { 16893ad22c62SMaxim Patlasov if (attr->ia_valid & ATTR_MTIME) 1690b0aa7606SMaxim Patlasov inode->i_mtime = attr->ia_mtime; 16913ad22c62SMaxim Patlasov if (attr->ia_valid & ATTR_CTIME) 16923ad22c62SMaxim Patlasov inode->i_ctime = attr->ia_ctime; 16931e18bda8SMiklos Szeredi /* FIXME: clear I_DIRTY_SYNC? */ 1694b0aa7606SMaxim Patlasov } 1695b0aa7606SMaxim Patlasov 16963be5a52bSMiklos Szeredi fuse_change_attributes_common(inode, &outarg.attr, 16973be5a52bSMiklos Szeredi attr_timeout(&outarg)); 16983be5a52bSMiklos Szeredi oldsize = inode->i_size; 16998373200bSPavel Emelyanov /* see the comment in fuse_change_attributes() */ 17008373200bSPavel Emelyanov if (!is_wb || is_truncate || !S_ISREG(inode->i_mode)) 17013be5a52bSMiklos Szeredi i_size_write(inode, outarg.attr.size); 17023be5a52bSMiklos Szeredi 17033be5a52bSMiklos Szeredi if (is_truncate) { 17043be5a52bSMiklos Szeredi /* NOTE: this may release/reacquire fc->lock */ 17053be5a52bSMiklos Szeredi __fuse_release_nowrite(inode); 17063be5a52bSMiklos Szeredi } 17073be5a52bSMiklos Szeredi spin_unlock(&fc->lock); 17083be5a52bSMiklos Szeredi 17093be5a52bSMiklos Szeredi /* 17103be5a52bSMiklos Szeredi * Only call invalidate_inode_pages2() after removing 17113be5a52bSMiklos Szeredi * FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock. 17123be5a52bSMiklos Szeredi */ 17138373200bSPavel Emelyanov if ((is_truncate || !is_wb) && 17148373200bSPavel Emelyanov S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) { 17157caef267SKirill A. Shutemov truncate_pagecache(inode, outarg.attr.size); 17163be5a52bSMiklos Szeredi invalidate_inode_pages2(inode->i_mapping); 17173be5a52bSMiklos Szeredi } 17183be5a52bSMiklos Szeredi 171906a7c3c2SMaxim Patlasov clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); 1720e00d2c2dSMiklos Szeredi return 0; 17213be5a52bSMiklos Szeredi 17223be5a52bSMiklos Szeredi error: 17233be5a52bSMiklos Szeredi if (is_truncate) 17243be5a52bSMiklos Szeredi fuse_release_nowrite(inode); 17253be5a52bSMiklos Szeredi 172606a7c3c2SMaxim Patlasov clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); 17273be5a52bSMiklos Szeredi return err; 17289e6268dbSMiklos Szeredi } 17299e6268dbSMiklos Szeredi 173049d4914fSMiklos Szeredi static int fuse_setattr(struct dentry *entry, struct iattr *attr) 173149d4914fSMiklos Szeredi { 17322b0143b5SDavid Howells struct inode *inode = d_inode(entry); 17335e940c1dSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1734a09f99edSMiklos Szeredi struct file *file = (attr->ia_valid & ATTR_FILE) ? attr->ia_file : NULL; 17355e2b8828SMiklos Szeredi int ret; 1736efb9fa9eSMaxim Patlasov 1737efb9fa9eSMaxim Patlasov if (!fuse_allow_current_process(get_fuse_conn(inode))) 1738efb9fa9eSMaxim Patlasov return -EACCES; 1739efb9fa9eSMaxim Patlasov 1740a09f99edSMiklos Szeredi if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) { 1741a09f99edSMiklos Szeredi attr->ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | 1742a09f99edSMiklos Szeredi ATTR_MODE); 17435e940c1dSMiklos Szeredi 1744a09f99edSMiklos Szeredi /* 17455e940c1dSMiklos Szeredi * The only sane way to reliably kill suid/sgid is to do it in 17465e940c1dSMiklos Szeredi * the userspace filesystem 17475e940c1dSMiklos Szeredi * 17485e940c1dSMiklos Szeredi * This should be done on write(), truncate() and chown(). 17495e940c1dSMiklos Szeredi */ 17505e940c1dSMiklos Szeredi if (!fc->handle_killpriv) { 17515e940c1dSMiklos Szeredi /* 17525e940c1dSMiklos Szeredi * ia_mode calculation may have used stale i_mode. 17535e940c1dSMiklos Szeredi * Refresh and recalculate. 1754a09f99edSMiklos Szeredi */ 1755a09f99edSMiklos Szeredi ret = fuse_do_getattr(inode, NULL, file); 1756a09f99edSMiklos Szeredi if (ret) 1757a09f99edSMiklos Szeredi return ret; 1758a09f99edSMiklos Szeredi 1759a09f99edSMiklos Szeredi attr->ia_mode = inode->i_mode; 1760c01638f5SMiklos Szeredi if (inode->i_mode & S_ISUID) { 1761a09f99edSMiklos Szeredi attr->ia_valid |= ATTR_MODE; 1762a09f99edSMiklos Szeredi attr->ia_mode &= ~S_ISUID; 1763a09f99edSMiklos Szeredi } 1764c01638f5SMiklos Szeredi if ((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { 1765a09f99edSMiklos Szeredi attr->ia_valid |= ATTR_MODE; 1766a09f99edSMiklos Szeredi attr->ia_mode &= ~S_ISGID; 1767a09f99edSMiklos Szeredi } 1768a09f99edSMiklos Szeredi } 17695e940c1dSMiklos Szeredi } 1770a09f99edSMiklos Szeredi if (!attr->ia_valid) 1771a09f99edSMiklos Szeredi return 0; 1772a09f99edSMiklos Szeredi 1773abb5a14fSLinus Torvalds ret = fuse_do_setattr(entry, attr, file); 17745e2b8828SMiklos Szeredi if (!ret) { 177560bcc88aSSeth Forshee /* 177660bcc88aSSeth Forshee * If filesystem supports acls it may have updated acl xattrs in 177760bcc88aSSeth Forshee * the filesystem, so forget cached acls for the inode. 177860bcc88aSSeth Forshee */ 177960bcc88aSSeth Forshee if (fc->posix_acl) 178060bcc88aSSeth Forshee forget_all_cached_acls(inode); 178160bcc88aSSeth Forshee 17825e2b8828SMiklos Szeredi /* Directory mode changed, may need to revalidate access */ 17835e2b8828SMiklos Szeredi if (d_is_dir(entry) && (attr->ia_valid & ATTR_MODE)) 17845e2b8828SMiklos Szeredi fuse_invalidate_entry_cache(entry); 17855e2b8828SMiklos Szeredi } 17865e2b8828SMiklos Szeredi return ret; 178749d4914fSMiklos Szeredi } 178849d4914fSMiklos Szeredi 1789a528d35eSDavid Howells static int fuse_getattr(const struct path *path, struct kstat *stat, 1790a528d35eSDavid Howells u32 request_mask, unsigned int flags) 1791e5e5558eSMiklos Szeredi { 1792a528d35eSDavid Howells struct inode *inode = d_inode(path->dentry); 1793244f6385SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1794244f6385SMiklos Szeredi 1795c2132c1bSAnatol Pomozov if (!fuse_allow_current_process(fc)) 1796244f6385SMiklos Szeredi return -EACCES; 1797244f6385SMiklos Szeredi 1798*ff1b89f3SMiklos Szeredi return fuse_update_get_attr(inode, NULL, stat, flags); 1799e5e5558eSMiklos Szeredi } 1800e5e5558eSMiklos Szeredi 1801754661f1SArjan van de Ven static const struct inode_operations fuse_dir_inode_operations = { 1802e5e5558eSMiklos Szeredi .lookup = fuse_lookup, 18039e6268dbSMiklos Szeredi .mkdir = fuse_mkdir, 18049e6268dbSMiklos Szeredi .symlink = fuse_symlink, 18059e6268dbSMiklos Szeredi .unlink = fuse_unlink, 18069e6268dbSMiklos Szeredi .rmdir = fuse_rmdir, 18072773bf00SMiklos Szeredi .rename = fuse_rename2, 18089e6268dbSMiklos Szeredi .link = fuse_link, 18099e6268dbSMiklos Szeredi .setattr = fuse_setattr, 18109e6268dbSMiklos Szeredi .create = fuse_create, 1811c8ccbe03SMiklos Szeredi .atomic_open = fuse_atomic_open, 18129e6268dbSMiklos Szeredi .mknod = fuse_mknod, 1813e5e5558eSMiklos Szeredi .permission = fuse_permission, 1814e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 181592a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 181660bcc88aSSeth Forshee .get_acl = fuse_get_acl, 181760bcc88aSSeth Forshee .set_acl = fuse_set_acl, 1818e5e5558eSMiklos Szeredi }; 1819e5e5558eSMiklos Szeredi 18204b6f5d20SArjan van de Ven static const struct file_operations fuse_dir_operations = { 1821b6aeadedSMiklos Szeredi .llseek = generic_file_llseek, 1822e5e5558eSMiklos Szeredi .read = generic_read_dir, 1823d9b3dbdcSAl Viro .iterate_shared = fuse_readdir, 1824e5e5558eSMiklos Szeredi .open = fuse_dir_open, 1825e5e5558eSMiklos Szeredi .release = fuse_dir_release, 182682547981SMiklos Szeredi .fsync = fuse_dir_fsync, 1827b18da0c5SMiklos Szeredi .unlocked_ioctl = fuse_dir_ioctl, 1828b18da0c5SMiklos Szeredi .compat_ioctl = fuse_dir_compat_ioctl, 1829e5e5558eSMiklos Szeredi }; 1830e5e5558eSMiklos Szeredi 1831754661f1SArjan van de Ven static const struct inode_operations fuse_common_inode_operations = { 18329e6268dbSMiklos Szeredi .setattr = fuse_setattr, 1833e5e5558eSMiklos Szeredi .permission = fuse_permission, 1834e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 183592a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 183660bcc88aSSeth Forshee .get_acl = fuse_get_acl, 183760bcc88aSSeth Forshee .set_acl = fuse_set_acl, 1838e5e5558eSMiklos Szeredi }; 1839e5e5558eSMiklos Szeredi 1840754661f1SArjan van de Ven static const struct inode_operations fuse_symlink_inode_operations = { 18419e6268dbSMiklos Szeredi .setattr = fuse_setattr, 18426b255391SAl Viro .get_link = fuse_get_link, 1843e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 184492a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 1845e5e5558eSMiklos Szeredi }; 1846e5e5558eSMiklos Szeredi 1847e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode) 1848e5e5558eSMiklos Szeredi { 1849e5e5558eSMiklos Szeredi inode->i_op = &fuse_common_inode_operations; 1850e5e5558eSMiklos Szeredi } 1851e5e5558eSMiklos Szeredi 1852e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode) 1853e5e5558eSMiklos Szeredi { 1854e5e5558eSMiklos Szeredi inode->i_op = &fuse_dir_inode_operations; 1855e5e5558eSMiklos Szeredi inode->i_fop = &fuse_dir_operations; 1856e5e5558eSMiklos Szeredi } 1857e5e5558eSMiklos Szeredi 1858e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode) 1859e5e5558eSMiklos Szeredi { 1860e5e5558eSMiklos Szeredi inode->i_op = &fuse_symlink_inode_operations; 1861e5e5558eSMiklos Szeredi } 1862