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; 861499dcf20SEric W. Biederman stat->uid = make_kuid(&init_user_ns, attr->uid); 862499dcf20SEric W. Biederman stat->gid = make_kgid(&init_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, 9275b97eeacSMiklos Szeredi struct kstat *stat) 928bcb4be80SMiklos Szeredi { 929bcb4be80SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 9305b97eeacSMiklos Szeredi int err = 0; 931bcb4be80SMiklos Szeredi 932126b9d43SMiklos Szeredi if (time_before64(fi->i_time, get_jiffies_64())) { 93360bcc88aSSeth Forshee forget_all_cached_acls(inode); 934bcb4be80SMiklos Szeredi err = fuse_do_getattr(inode, stat, file); 9355b97eeacSMiklos Szeredi } else if (stat) { 936bcb4be80SMiklos Szeredi generic_fillattr(inode, stat); 937bcb4be80SMiklos Szeredi stat->mode = fi->orig_i_mode; 93845c72cd7SPavel Shilovsky stat->ino = fi->orig_ino; 939bcb4be80SMiklos Szeredi } 940bcb4be80SMiklos Szeredi 941bcb4be80SMiklos Szeredi return err; 942bcb4be80SMiklos Szeredi } 943bcb4be80SMiklos Szeredi 9445b97eeacSMiklos Szeredi int fuse_update_attributes(struct inode *inode, struct file *file) 9455b97eeacSMiklos Szeredi { 9465b97eeacSMiklos Szeredi return fuse_update_get_attr(inode, file, NULL); 9475b97eeacSMiklos Szeredi } 9485b97eeacSMiklos Szeredi 9493b463ae0SJohn Muir int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, 950451d0f59SJohn Muir u64 child_nodeid, struct qstr *name) 9513b463ae0SJohn Muir { 9523b463ae0SJohn Muir int err = -ENOTDIR; 9533b463ae0SJohn Muir struct inode *parent; 9543b463ae0SJohn Muir struct dentry *dir; 9553b463ae0SJohn Muir struct dentry *entry; 9563b463ae0SJohn Muir 9573b463ae0SJohn Muir parent = ilookup5(sb, parent_nodeid, fuse_inode_eq, &parent_nodeid); 9583b463ae0SJohn Muir if (!parent) 9593b463ae0SJohn Muir return -ENOENT; 9603b463ae0SJohn Muir 9615955102cSAl Viro inode_lock(parent); 9623b463ae0SJohn Muir if (!S_ISDIR(parent->i_mode)) 9633b463ae0SJohn Muir goto unlock; 9643b463ae0SJohn Muir 9653b463ae0SJohn Muir err = -ENOENT; 9663b463ae0SJohn Muir dir = d_find_alias(parent); 9673b463ae0SJohn Muir if (!dir) 9683b463ae0SJohn Muir goto unlock; 9693b463ae0SJohn Muir 9708387ff25SLinus Torvalds name->hash = full_name_hash(dir, name->name, name->len); 9713b463ae0SJohn Muir entry = d_lookup(dir, name); 9723b463ae0SJohn Muir dput(dir); 9733b463ae0SJohn Muir if (!entry) 9743b463ae0SJohn Muir goto unlock; 9753b463ae0SJohn Muir 9763b463ae0SJohn Muir fuse_invalidate_attr(parent); 9773b463ae0SJohn Muir fuse_invalidate_entry(entry); 978451d0f59SJohn Muir 9792b0143b5SDavid Howells if (child_nodeid != 0 && d_really_is_positive(entry)) { 9805955102cSAl Viro inode_lock(d_inode(entry)); 9812b0143b5SDavid Howells if (get_node_id(d_inode(entry)) != child_nodeid) { 982451d0f59SJohn Muir err = -ENOENT; 983451d0f59SJohn Muir goto badentry; 984451d0f59SJohn Muir } 985451d0f59SJohn Muir if (d_mountpoint(entry)) { 986451d0f59SJohn Muir err = -EBUSY; 987451d0f59SJohn Muir goto badentry; 988451d0f59SJohn Muir } 989e36cb0b8SDavid Howells if (d_is_dir(entry)) { 990451d0f59SJohn Muir shrink_dcache_parent(entry); 991451d0f59SJohn Muir if (!simple_empty(entry)) { 992451d0f59SJohn Muir err = -ENOTEMPTY; 993451d0f59SJohn Muir goto badentry; 994451d0f59SJohn Muir } 9952b0143b5SDavid Howells d_inode(entry)->i_flags |= S_DEAD; 996451d0f59SJohn Muir } 997451d0f59SJohn Muir dont_mount(entry); 9982b0143b5SDavid Howells clear_nlink(d_inode(entry)); 9993b463ae0SJohn Muir err = 0; 1000451d0f59SJohn Muir badentry: 10015955102cSAl Viro inode_unlock(d_inode(entry)); 1002451d0f59SJohn Muir if (!err) 1003451d0f59SJohn Muir d_delete(entry); 1004451d0f59SJohn Muir } else { 1005451d0f59SJohn Muir err = 0; 1006451d0f59SJohn Muir } 1007451d0f59SJohn Muir dput(entry); 10083b463ae0SJohn Muir 10093b463ae0SJohn Muir unlock: 10105955102cSAl Viro inode_unlock(parent); 10113b463ae0SJohn Muir iput(parent); 10123b463ae0SJohn Muir return err; 10133b463ae0SJohn Muir } 10143b463ae0SJohn Muir 101587729a55SMiklos Szeredi /* 101687729a55SMiklos Szeredi * Calling into a user-controlled filesystem gives the filesystem 1017c2132c1bSAnatol Pomozov * daemon ptrace-like capabilities over the current process. This 101887729a55SMiklos Szeredi * means, that the filesystem daemon is able to record the exact 101987729a55SMiklos Szeredi * filesystem operations performed, and can also control the behavior 102087729a55SMiklos Szeredi * of the requester process in otherwise impossible ways. For example 102187729a55SMiklos Szeredi * it can delay the operation for arbitrary length of time allowing 102287729a55SMiklos Szeredi * DoS against the requester. 102387729a55SMiklos Szeredi * 102487729a55SMiklos Szeredi * For this reason only those processes can call into the filesystem, 102587729a55SMiklos Szeredi * for which the owner of the mount has ptrace privilege. This 102687729a55SMiklos Szeredi * excludes processes started by other users, suid or sgid processes. 102787729a55SMiklos Szeredi */ 1028c2132c1bSAnatol Pomozov int fuse_allow_current_process(struct fuse_conn *fc) 102987729a55SMiklos Szeredi { 1030c69e8d9cSDavid Howells const struct cred *cred; 1031c69e8d9cSDavid Howells 103229433a29SMiklos Szeredi if (fc->allow_other) 103387729a55SMiklos Szeredi return 1; 103487729a55SMiklos Szeredi 1035c2132c1bSAnatol Pomozov cred = current_cred(); 1036499dcf20SEric W. Biederman if (uid_eq(cred->euid, fc->user_id) && 1037499dcf20SEric W. Biederman uid_eq(cred->suid, fc->user_id) && 1038499dcf20SEric W. Biederman uid_eq(cred->uid, fc->user_id) && 1039499dcf20SEric W. Biederman gid_eq(cred->egid, fc->group_id) && 1040499dcf20SEric W. Biederman gid_eq(cred->sgid, fc->group_id) && 1041499dcf20SEric W. Biederman gid_eq(cred->gid, fc->group_id)) 1042c2132c1bSAnatol Pomozov return 1; 104387729a55SMiklos Szeredi 1044c2132c1bSAnatol Pomozov return 0; 104587729a55SMiklos Szeredi } 104687729a55SMiklos Szeredi 104731d40d74SMiklos Szeredi static int fuse_access(struct inode *inode, int mask) 104831d40d74SMiklos Szeredi { 104931d40d74SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 10507078187aSMiklos Szeredi FUSE_ARGS(args); 105131d40d74SMiklos Szeredi struct fuse_access_in inarg; 105231d40d74SMiklos Szeredi int err; 105331d40d74SMiklos Szeredi 1054698fa1d1SMiklos Szeredi BUG_ON(mask & MAY_NOT_BLOCK); 1055698fa1d1SMiklos Szeredi 105631d40d74SMiklos Szeredi if (fc->no_access) 105731d40d74SMiklos Szeredi return 0; 105831d40d74SMiklos Szeredi 105931d40d74SMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 1060e6305c43SAl Viro inarg.mask = mask & (MAY_READ | MAY_WRITE | MAY_EXEC); 10617078187aSMiklos Szeredi args.in.h.opcode = FUSE_ACCESS; 10627078187aSMiklos Szeredi args.in.h.nodeid = get_node_id(inode); 10637078187aSMiklos Szeredi args.in.numargs = 1; 10647078187aSMiklos Szeredi args.in.args[0].size = sizeof(inarg); 10657078187aSMiklos Szeredi args.in.args[0].value = &inarg; 10667078187aSMiklos Szeredi err = fuse_simple_request(fc, &args); 106731d40d74SMiklos Szeredi if (err == -ENOSYS) { 106831d40d74SMiklos Szeredi fc->no_access = 1; 106931d40d74SMiklos Szeredi err = 0; 107031d40d74SMiklos Szeredi } 107131d40d74SMiklos Szeredi return err; 107231d40d74SMiklos Szeredi } 107331d40d74SMiklos Szeredi 107410556cb2SAl Viro static int fuse_perm_getattr(struct inode *inode, int mask) 107519690ddbSMiklos Szeredi { 107610556cb2SAl Viro if (mask & MAY_NOT_BLOCK) 107719690ddbSMiklos Szeredi return -ECHILD; 107819690ddbSMiklos Szeredi 107960bcc88aSSeth Forshee forget_all_cached_acls(inode); 108019690ddbSMiklos Szeredi return fuse_do_getattr(inode, NULL, NULL); 108119690ddbSMiklos Szeredi } 108219690ddbSMiklos Szeredi 10836f9f1180SMiklos Szeredi /* 10846f9f1180SMiklos Szeredi * Check permission. The two basic access models of FUSE are: 10856f9f1180SMiklos Szeredi * 10866f9f1180SMiklos Szeredi * 1) Local access checking ('default_permissions' mount option) based 10876f9f1180SMiklos Szeredi * on file mode. This is the plain old disk filesystem permission 10886f9f1180SMiklos Szeredi * modell. 10896f9f1180SMiklos Szeredi * 10906f9f1180SMiklos Szeredi * 2) "Remote" access checking, where server is responsible for 10916f9f1180SMiklos Szeredi * checking permission in each inode operation. An exception to this 10926f9f1180SMiklos Szeredi * is if ->permission() was invoked from sys_access() in which case an 10936f9f1180SMiklos Szeredi * access request is sent. Execute permission is still checked 10946f9f1180SMiklos Szeredi * locally based on file mode. 10956f9f1180SMiklos Szeredi */ 109610556cb2SAl Viro static int fuse_permission(struct inode *inode, int mask) 1097e5e5558eSMiklos Szeredi { 1098e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1099244f6385SMiklos Szeredi bool refreshed = false; 1100244f6385SMiklos Szeredi int err = 0; 1101e5e5558eSMiklos Szeredi 1102c2132c1bSAnatol Pomozov if (!fuse_allow_current_process(fc)) 1103e5e5558eSMiklos Szeredi return -EACCES; 1104244f6385SMiklos Szeredi 1105244f6385SMiklos Szeredi /* 1106e8e96157SMiklos Szeredi * If attributes are needed, refresh them before proceeding 1107244f6385SMiklos Szeredi */ 110829433a29SMiklos Szeredi if (fc->default_permissions || 1109e8e96157SMiklos Szeredi ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { 111019690ddbSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 111119690ddbSMiklos Szeredi 1112126b9d43SMiklos Szeredi if (time_before64(fi->i_time, get_jiffies_64())) { 111319690ddbSMiklos Szeredi refreshed = true; 111419690ddbSMiklos Szeredi 111510556cb2SAl Viro err = fuse_perm_getattr(inode, mask); 1116244f6385SMiklos Szeredi if (err) 1117244f6385SMiklos Szeredi return err; 11181fb69e78SMiklos Szeredi } 111919690ddbSMiklos Szeredi } 1120244f6385SMiklos Szeredi 112129433a29SMiklos Szeredi if (fc->default_permissions) { 11222830ba7fSAl Viro err = generic_permission(inode, mask); 11231e9a4ed9SMiklos Szeredi 11241e9a4ed9SMiklos Szeredi /* If permission is denied, try to refresh file 11251e9a4ed9SMiklos Szeredi attributes. This is also needed, because the root 11261e9a4ed9SMiklos Szeredi node will at first have no permissions */ 1127244f6385SMiklos Szeredi if (err == -EACCES && !refreshed) { 112810556cb2SAl Viro err = fuse_perm_getattr(inode, mask); 11291e9a4ed9SMiklos Szeredi if (!err) 11302830ba7fSAl Viro err = generic_permission(inode, mask); 11311e9a4ed9SMiklos Szeredi } 11321e9a4ed9SMiklos Szeredi 11336f9f1180SMiklos Szeredi /* Note: the opposite of the above test does not 11346f9f1180SMiklos Szeredi exist. So if permissions are revoked this won't be 11356f9f1180SMiklos Szeredi noticed immediately, only after the attribute 11366f9f1180SMiklos Szeredi timeout has expired */ 11379cfcac81SEric Paris } else if (mask & (MAY_ACCESS | MAY_CHDIR)) { 1138e8e96157SMiklos Szeredi err = fuse_access(inode, mask); 1139e8e96157SMiklos Szeredi } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { 1140e8e96157SMiklos Szeredi if (!(inode->i_mode & S_IXUGO)) { 1141e8e96157SMiklos Szeredi if (refreshed) 1142e5e5558eSMiklos Szeredi return -EACCES; 114331d40d74SMiklos Szeredi 114410556cb2SAl Viro err = fuse_perm_getattr(inode, mask); 1145e8e96157SMiklos Szeredi if (!err && !(inode->i_mode & S_IXUGO)) 1146e8e96157SMiklos Szeredi return -EACCES; 1147e8e96157SMiklos Szeredi } 1148e5e5558eSMiklos Szeredi } 1149244f6385SMiklos Szeredi return err; 1150e5e5558eSMiklos Szeredi } 1151e5e5558eSMiklos Szeredi 1152e5e5558eSMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file, 11538d3af7f3SAl Viro struct dir_context *ctx) 1154e5e5558eSMiklos Szeredi { 1155e5e5558eSMiklos Szeredi while (nbytes >= FUSE_NAME_OFFSET) { 1156e5e5558eSMiklos Szeredi struct fuse_dirent *dirent = (struct fuse_dirent *) buf; 1157e5e5558eSMiklos Szeredi size_t reclen = FUSE_DIRENT_SIZE(dirent); 1158e5e5558eSMiklos Szeredi if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) 1159e5e5558eSMiklos Szeredi return -EIO; 1160e5e5558eSMiklos Szeredi if (reclen > nbytes) 1161e5e5558eSMiklos Szeredi break; 1162efeb9e60SMiklos Szeredi if (memchr(dirent->name, '/', dirent->namelen) != NULL) 1163efeb9e60SMiklos Szeredi return -EIO; 1164e5e5558eSMiklos Szeredi 11658d3af7f3SAl Viro if (!dir_emit(ctx, dirent->name, dirent->namelen, 11668d3af7f3SAl Viro dirent->ino, dirent->type)) 1167e5e5558eSMiklos Szeredi break; 1168e5e5558eSMiklos Szeredi 1169e5e5558eSMiklos Szeredi buf += reclen; 1170e5e5558eSMiklos Szeredi nbytes -= reclen; 11718d3af7f3SAl Viro ctx->pos = dirent->off; 1172e5e5558eSMiklos Szeredi } 1173e5e5558eSMiklos Szeredi 1174e5e5558eSMiklos Szeredi return 0; 1175e5e5558eSMiklos Szeredi } 1176e5e5558eSMiklos Szeredi 11770b05b183SAnand V. Avati static int fuse_direntplus_link(struct file *file, 11780b05b183SAnand V. Avati struct fuse_direntplus *direntplus, 11790b05b183SAnand V. Avati u64 attr_version) 11800b05b183SAnand V. Avati { 11810b05b183SAnand V. Avati struct fuse_entry_out *o = &direntplus->entry_out; 11820b05b183SAnand V. Avati struct fuse_dirent *dirent = &direntplus->dirent; 11830b05b183SAnand V. Avati struct dentry *parent = file->f_path.dentry; 11840b05b183SAnand V. Avati struct qstr name = QSTR_INIT(dirent->name, dirent->namelen); 11850b05b183SAnand V. Avati struct dentry *dentry; 11860b05b183SAnand V. Avati struct dentry *alias; 11872b0143b5SDavid Howells struct inode *dir = d_inode(parent); 11880b05b183SAnand V. Avati struct fuse_conn *fc; 11890b05b183SAnand V. Avati struct inode *inode; 1190d9b3dbdcSAl Viro DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); 11910b05b183SAnand V. Avati 11920b05b183SAnand V. Avati if (!o->nodeid) { 11930b05b183SAnand V. Avati /* 11940b05b183SAnand V. Avati * Unlike in the case of fuse_lookup, zero nodeid does not mean 11950b05b183SAnand V. Avati * ENOENT. Instead, it only means the userspace filesystem did 11960b05b183SAnand V. Avati * not want to return attributes/handle for this entry. 11970b05b183SAnand V. Avati * 11980b05b183SAnand V. Avati * So do nothing. 11990b05b183SAnand V. Avati */ 12000b05b183SAnand V. Avati return 0; 12010b05b183SAnand V. Avati } 12020b05b183SAnand V. Avati 12030b05b183SAnand V. Avati if (name.name[0] == '.') { 12040b05b183SAnand V. Avati /* 12050b05b183SAnand V. Avati * We could potentially refresh the attributes of the directory 12060b05b183SAnand V. Avati * and its parent? 12070b05b183SAnand V. Avati */ 12080b05b183SAnand V. Avati if (name.len == 1) 12090b05b183SAnand V. Avati return 0; 12100b05b183SAnand V. Avati if (name.name[1] == '.' && name.len == 2) 12110b05b183SAnand V. Avati return 0; 12120b05b183SAnand V. Avati } 1213a28ef45cSMiklos Szeredi 1214a28ef45cSMiklos Szeredi if (invalid_nodeid(o->nodeid)) 1215a28ef45cSMiklos Szeredi return -EIO; 1216a28ef45cSMiklos Szeredi if (!fuse_valid_type(o->attr.mode)) 1217a28ef45cSMiklos Szeredi return -EIO; 1218a28ef45cSMiklos Szeredi 12190b05b183SAnand V. Avati fc = get_fuse_conn(dir); 12200b05b183SAnand V. Avati 12218387ff25SLinus Torvalds name.hash = full_name_hash(parent, name.name, name.len); 12220b05b183SAnand V. Avati dentry = d_lookup(parent, &name); 1223d9b3dbdcSAl Viro if (!dentry) { 1224d9b3dbdcSAl Viro retry: 1225d9b3dbdcSAl Viro dentry = d_alloc_parallel(parent, &name, &wq); 1226d9b3dbdcSAl Viro if (IS_ERR(dentry)) 1227d9b3dbdcSAl Viro return PTR_ERR(dentry); 1228d9b3dbdcSAl Viro } 1229d9b3dbdcSAl Viro if (!d_in_lookup(dentry)) { 1230d9b3dbdcSAl Viro struct fuse_inode *fi; 12312b0143b5SDavid Howells inode = d_inode(dentry); 1232d9b3dbdcSAl Viro if (!inode || 1233d9b3dbdcSAl Viro get_node_id(inode) != o->nodeid || 1234a28ef45cSMiklos Szeredi ((o->attr.mode ^ inode->i_mode) & S_IFMT)) { 12355542aa2fSEric W. Biederman d_invalidate(dentry); 1236d9b3dbdcSAl Viro dput(dentry); 1237d9b3dbdcSAl Viro goto retry; 1238d9b3dbdcSAl Viro } 1239d9b3dbdcSAl Viro if (is_bad_inode(inode)) { 1240d9b3dbdcSAl Viro dput(dentry); 1241d9b3dbdcSAl Viro return -EIO; 1242d9b3dbdcSAl Viro } 1243d9b3dbdcSAl Viro 12440b05b183SAnand V. Avati fi = get_fuse_inode(inode); 12450b05b183SAnand V. Avati spin_lock(&fc->lock); 12460b05b183SAnand V. Avati fi->nlookup++; 12470b05b183SAnand V. Avati spin_unlock(&fc->lock); 12480b05b183SAnand V. Avati 124960bcc88aSSeth Forshee forget_all_cached_acls(inode); 1250fa2b7213SMiklos Szeredi fuse_change_attributes(inode, &o->attr, 1251fa2b7213SMiklos Szeredi entry_attr_timeout(o), 1252fa2b7213SMiklos Szeredi attr_version); 12530b05b183SAnand V. Avati /* 1254d9b3dbdcSAl Viro * The other branch comes via fuse_iget() 12550b05b183SAnand V. Avati * which bumps nlookup inside 12560b05b183SAnand V. Avati */ 1257d9b3dbdcSAl Viro } else { 12580b05b183SAnand V. Avati inode = fuse_iget(dir->i_sb, o->nodeid, o->generation, 1259d9b3dbdcSAl Viro &o->attr, entry_attr_timeout(o), 1260d9b3dbdcSAl Viro attr_version); 12610b05b183SAnand V. Avati if (!inode) 1262d9b3dbdcSAl Viro inode = ERR_PTR(-ENOMEM); 12630b05b183SAnand V. Avati 126441d28bcaSAl Viro alias = d_splice_alias(inode, dentry); 1265d9b3dbdcSAl Viro d_lookup_done(dentry); 12660b05b183SAnand V. Avati if (alias) { 12670b05b183SAnand V. Avati dput(dentry); 12680b05b183SAnand V. Avati dentry = alias; 12690b05b183SAnand V. Avati } 1270d9b3dbdcSAl Viro if (IS_ERR(dentry)) 1271d9b3dbdcSAl Viro return PTR_ERR(dentry); 1272d9b3dbdcSAl Viro } 12736314efeeSMiklos Szeredi if (fc->readdirplus_auto) 12746314efeeSMiklos Szeredi set_bit(FUSE_I_INIT_RDPLUS, &get_fuse_inode(inode)->state); 12750b05b183SAnand V. Avati fuse_change_entry_timeout(dentry, o); 12760b05b183SAnand V. Avati 12770b05b183SAnand V. Avati dput(dentry); 1278d9b3dbdcSAl Viro return 0; 12790b05b183SAnand V. Avati } 12800b05b183SAnand V. Avati 12810b05b183SAnand V. Avati static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file, 12828d3af7f3SAl Viro struct dir_context *ctx, u64 attr_version) 12830b05b183SAnand V. Avati { 12840b05b183SAnand V. Avati struct fuse_direntplus *direntplus; 12850b05b183SAnand V. Avati struct fuse_dirent *dirent; 12860b05b183SAnand V. Avati size_t reclen; 12870b05b183SAnand V. Avati int over = 0; 12880b05b183SAnand V. Avati int ret; 12890b05b183SAnand V. Avati 12900b05b183SAnand V. Avati while (nbytes >= FUSE_NAME_OFFSET_DIRENTPLUS) { 12910b05b183SAnand V. Avati direntplus = (struct fuse_direntplus *) buf; 12920b05b183SAnand V. Avati dirent = &direntplus->dirent; 12930b05b183SAnand V. Avati reclen = FUSE_DIRENTPLUS_SIZE(direntplus); 12940b05b183SAnand V. Avati 12950b05b183SAnand V. Avati if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) 12960b05b183SAnand V. Avati return -EIO; 12970b05b183SAnand V. Avati if (reclen > nbytes) 12980b05b183SAnand V. Avati break; 1299efeb9e60SMiklos Szeredi if (memchr(dirent->name, '/', dirent->namelen) != NULL) 1300efeb9e60SMiklos Szeredi return -EIO; 13010b05b183SAnand V. Avati 13020b05b183SAnand V. Avati if (!over) { 13030b05b183SAnand V. Avati /* We fill entries into dstbuf only as much as 13040b05b183SAnand V. Avati it can hold. But we still continue iterating 13050b05b183SAnand V. Avati over remaining entries to link them. If not, 13060b05b183SAnand V. Avati we need to send a FORGET for each of those 13070b05b183SAnand V. Avati which we did not link. 13080b05b183SAnand V. Avati */ 13098d3af7f3SAl Viro over = !dir_emit(ctx, dirent->name, dirent->namelen, 13108d3af7f3SAl Viro dirent->ino, dirent->type); 1311*c6cdd514SMiklos Szeredi if (!over) 13128d3af7f3SAl Viro ctx->pos = dirent->off; 13130b05b183SAnand V. Avati } 13140b05b183SAnand V. Avati 13150b05b183SAnand V. Avati buf += reclen; 13160b05b183SAnand V. Avati nbytes -= reclen; 13170b05b183SAnand V. Avati 13180b05b183SAnand V. Avati ret = fuse_direntplus_link(file, direntplus, attr_version); 13190b05b183SAnand V. Avati if (ret) 13200b05b183SAnand V. Avati fuse_force_forget(file, direntplus->entry_out.nodeid); 13210b05b183SAnand V. Avati } 13220b05b183SAnand V. Avati 13230b05b183SAnand V. Avati return 0; 13240b05b183SAnand V. Avati } 13250b05b183SAnand V. Avati 13268d3af7f3SAl Viro static int fuse_readdir(struct file *file, struct dir_context *ctx) 1327e5e5558eSMiklos Szeredi { 13284582a4abSFeng Shuo int plus, err; 132904730fefSMiklos Szeredi size_t nbytes; 133004730fefSMiklos Szeredi struct page *page; 1331496ad9aaSAl Viro struct inode *inode = file_inode(file); 133204730fefSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1333248d86e8SMiklos Szeredi struct fuse_req *req; 13340b05b183SAnand V. Avati u64 attr_version = 0; 1335248d86e8SMiklos Szeredi 1336248d86e8SMiklos Szeredi if (is_bad_inode(inode)) 1337248d86e8SMiklos Szeredi return -EIO; 1338248d86e8SMiklos Szeredi 1339b111c8c0SMaxim Patlasov req = fuse_get_req(fc, 1); 1340ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1341ce1d5a49SMiklos Szeredi return PTR_ERR(req); 1342e5e5558eSMiklos Szeredi 134304730fefSMiklos Szeredi page = alloc_page(GFP_KERNEL); 134404730fefSMiklos Szeredi if (!page) { 134504730fefSMiklos Szeredi fuse_put_request(fc, req); 1346e5e5558eSMiklos Szeredi return -ENOMEM; 134704730fefSMiklos Szeredi } 13484582a4abSFeng Shuo 13498d3af7f3SAl Viro plus = fuse_use_readdirplus(inode, ctx); 1350f4975c67SMiklos Szeredi req->out.argpages = 1; 135104730fefSMiklos Szeredi req->num_pages = 1; 135204730fefSMiklos Szeredi req->pages[0] = page; 135385f40aecSMaxim Patlasov req->page_descs[0].length = PAGE_SIZE; 13544582a4abSFeng Shuo if (plus) { 13550b05b183SAnand V. Avati attr_version = fuse_get_attr_version(fc); 13568d3af7f3SAl Viro fuse_read_fill(req, file, ctx->pos, PAGE_SIZE, 13570b05b183SAnand V. Avati FUSE_READDIRPLUS); 13580b05b183SAnand V. Avati } else { 13598d3af7f3SAl Viro fuse_read_fill(req, file, ctx->pos, PAGE_SIZE, 13600b05b183SAnand V. Avati FUSE_READDIR); 13610b05b183SAnand V. Avati } 13625c672ab3SMiklos Szeredi fuse_lock_inode(inode); 1363b93f858aSTejun Heo fuse_request_send(fc, req); 13645c672ab3SMiklos Szeredi fuse_unlock_inode(inode); 1365361b1eb5SMiklos Szeredi nbytes = req->out.args[0].size; 136604730fefSMiklos Szeredi err = req->out.h.error; 136704730fefSMiklos Szeredi fuse_put_request(fc, req); 13680b05b183SAnand V. Avati if (!err) { 13694582a4abSFeng Shuo if (plus) { 13700b05b183SAnand V. Avati err = parse_dirplusfile(page_address(page), nbytes, 13718d3af7f3SAl Viro file, ctx, 13720b05b183SAnand V. Avati attr_version); 13730b05b183SAnand V. Avati } else { 13740b05b183SAnand V. Avati err = parse_dirfile(page_address(page), nbytes, file, 13758d3af7f3SAl Viro ctx); 13760b05b183SAnand V. Avati } 13770b05b183SAnand V. Avati } 1378e5e5558eSMiklos Szeredi 137904730fefSMiklos Szeredi __free_page(page); 1380451418fcSAndrew Gallagher fuse_invalidate_atime(inode); 138104730fefSMiklos Szeredi return err; 1382e5e5558eSMiklos Szeredi } 1383e5e5558eSMiklos Szeredi 13846b255391SAl Viro static const char *fuse_get_link(struct dentry *dentry, 1385fceef393SAl Viro struct inode *inode, 1386fceef393SAl Viro struct delayed_call *done) 1387e5e5558eSMiklos Szeredi { 1388e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 13897078187aSMiklos Szeredi FUSE_ARGS(args); 1390e5e5558eSMiklos Szeredi char *link; 13917078187aSMiklos Szeredi ssize_t ret; 1392e5e5558eSMiklos Szeredi 13936b255391SAl Viro if (!dentry) 13946b255391SAl Viro return ERR_PTR(-ECHILD); 13956b255391SAl Viro 1396cd3417c8SAl Viro link = kmalloc(PAGE_SIZE, GFP_KERNEL); 13977078187aSMiklos Szeredi if (!link) 13987078187aSMiklos Szeredi return ERR_PTR(-ENOMEM); 13997078187aSMiklos Szeredi 14007078187aSMiklos Szeredi args.in.h.opcode = FUSE_READLINK; 14017078187aSMiklos Szeredi args.in.h.nodeid = get_node_id(inode); 14027078187aSMiklos Szeredi args.out.argvar = 1; 14037078187aSMiklos Szeredi args.out.numargs = 1; 14047078187aSMiklos Szeredi args.out.args[0].size = PAGE_SIZE - 1; 14057078187aSMiklos Szeredi args.out.args[0].value = link; 14067078187aSMiklos Szeredi ret = fuse_simple_request(fc, &args); 14077078187aSMiklos Szeredi if (ret < 0) { 1408cd3417c8SAl Viro kfree(link); 14097078187aSMiklos Szeredi link = ERR_PTR(ret); 14107078187aSMiklos Szeredi } else { 14117078187aSMiklos Szeredi link[ret] = '\0'; 1412fceef393SAl Viro set_delayed_call(done, kfree_link, link); 14137078187aSMiklos Szeredi } 1414451418fcSAndrew Gallagher fuse_invalidate_atime(inode); 1415e5e5558eSMiklos Szeredi return link; 1416e5e5558eSMiklos Szeredi } 1417e5e5558eSMiklos Szeredi 1418e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file) 1419e5e5558eSMiklos Szeredi { 142091fe96b4SMiklos Szeredi return fuse_open_common(inode, file, true); 1421e5e5558eSMiklos Szeredi } 1422e5e5558eSMiklos Szeredi 1423e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file) 1424e5e5558eSMiklos Szeredi { 14258b0797a4SMiklos Szeredi fuse_release_common(file, FUSE_RELEASEDIR); 14268b0797a4SMiklos Szeredi 14278b0797a4SMiklos Szeredi return 0; 1428e5e5558eSMiklos Szeredi } 1429e5e5558eSMiklos Szeredi 143002c24a82SJosef Bacik static int fuse_dir_fsync(struct file *file, loff_t start, loff_t end, 143102c24a82SJosef Bacik int datasync) 143282547981SMiklos Szeredi { 143302c24a82SJosef Bacik return fuse_fsync_common(file, start, end, datasync, 1); 143482547981SMiklos Szeredi } 143582547981SMiklos Szeredi 1436b18da0c5SMiklos Szeredi static long fuse_dir_ioctl(struct file *file, unsigned int cmd, 1437b18da0c5SMiklos Szeredi unsigned long arg) 1438b18da0c5SMiklos Szeredi { 1439b18da0c5SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(file->f_mapping->host); 1440b18da0c5SMiklos Szeredi 1441b18da0c5SMiklos Szeredi /* FUSE_IOCTL_DIR only supported for API version >= 7.18 */ 1442b18da0c5SMiklos Szeredi if (fc->minor < 18) 1443b18da0c5SMiklos Szeredi return -ENOTTY; 1444b18da0c5SMiklos Szeredi 1445b18da0c5SMiklos Szeredi return fuse_ioctl_common(file, cmd, arg, FUSE_IOCTL_DIR); 1446b18da0c5SMiklos Szeredi } 1447b18da0c5SMiklos Szeredi 1448b18da0c5SMiklos Szeredi static long fuse_dir_compat_ioctl(struct file *file, unsigned int cmd, 1449b18da0c5SMiklos Szeredi unsigned long arg) 1450b18da0c5SMiklos Szeredi { 1451b18da0c5SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(file->f_mapping->host); 1452b18da0c5SMiklos Szeredi 1453b18da0c5SMiklos Szeredi if (fc->minor < 18) 1454b18da0c5SMiklos Szeredi return -ENOTTY; 1455b18da0c5SMiklos Szeredi 1456b18da0c5SMiklos Szeredi return fuse_ioctl_common(file, cmd, arg, 1457b18da0c5SMiklos Szeredi FUSE_IOCTL_COMPAT | FUSE_IOCTL_DIR); 1458b18da0c5SMiklos Szeredi } 1459b18da0c5SMiklos Szeredi 1460b0aa7606SMaxim Patlasov static bool update_mtime(unsigned ivalid, bool trust_local_mtime) 146117637cbaSMiklos Szeredi { 146217637cbaSMiklos Szeredi /* Always update if mtime is explicitly set */ 146317637cbaSMiklos Szeredi if (ivalid & ATTR_MTIME_SET) 146417637cbaSMiklos Szeredi return true; 146517637cbaSMiklos Szeredi 1466b0aa7606SMaxim Patlasov /* Or if kernel i_mtime is the official one */ 1467b0aa7606SMaxim Patlasov if (trust_local_mtime) 1468b0aa7606SMaxim Patlasov return true; 1469b0aa7606SMaxim Patlasov 147017637cbaSMiklos Szeredi /* If it's an open(O_TRUNC) or an ftruncate(), don't update */ 147117637cbaSMiklos Szeredi if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE))) 147217637cbaSMiklos Szeredi return false; 147317637cbaSMiklos Szeredi 147417637cbaSMiklos Szeredi /* In all other cases update */ 147517637cbaSMiklos Szeredi return true; 147617637cbaSMiklos Szeredi } 147717637cbaSMiklos Szeredi 1478b0aa7606SMaxim Patlasov static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg, 14793ad22c62SMaxim Patlasov bool trust_local_cmtime) 14809e6268dbSMiklos Szeredi { 14819e6268dbSMiklos Szeredi unsigned ivalid = iattr->ia_valid; 14829e6268dbSMiklos Szeredi 14839e6268dbSMiklos Szeredi if (ivalid & ATTR_MODE) 1484befc649cSMiklos Szeredi arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode; 14859e6268dbSMiklos Szeredi if (ivalid & ATTR_UID) 1486499dcf20SEric W. Biederman arg->valid |= FATTR_UID, arg->uid = from_kuid(&init_user_ns, iattr->ia_uid); 14879e6268dbSMiklos Szeredi if (ivalid & ATTR_GID) 1488499dcf20SEric W. Biederman arg->valid |= FATTR_GID, arg->gid = from_kgid(&init_user_ns, iattr->ia_gid); 14899e6268dbSMiklos Szeredi if (ivalid & ATTR_SIZE) 1490befc649cSMiklos Szeredi arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size; 149117637cbaSMiklos Szeredi if (ivalid & ATTR_ATIME) { 149217637cbaSMiklos Szeredi arg->valid |= FATTR_ATIME; 1493befc649cSMiklos Szeredi arg->atime = iattr->ia_atime.tv_sec; 149417637cbaSMiklos Szeredi arg->atimensec = iattr->ia_atime.tv_nsec; 149517637cbaSMiklos Szeredi if (!(ivalid & ATTR_ATIME_SET)) 149617637cbaSMiklos Szeredi arg->valid |= FATTR_ATIME_NOW; 149717637cbaSMiklos Szeredi } 14983ad22c62SMaxim Patlasov if ((ivalid & ATTR_MTIME) && update_mtime(ivalid, trust_local_cmtime)) { 149917637cbaSMiklos Szeredi arg->valid |= FATTR_MTIME; 1500befc649cSMiklos Szeredi arg->mtime = iattr->ia_mtime.tv_sec; 150117637cbaSMiklos Szeredi arg->mtimensec = iattr->ia_mtime.tv_nsec; 15023ad22c62SMaxim Patlasov if (!(ivalid & ATTR_MTIME_SET) && !trust_local_cmtime) 150317637cbaSMiklos Szeredi arg->valid |= FATTR_MTIME_NOW; 15049e6268dbSMiklos Szeredi } 15053ad22c62SMaxim Patlasov if ((ivalid & ATTR_CTIME) && trust_local_cmtime) { 15063ad22c62SMaxim Patlasov arg->valid |= FATTR_CTIME; 15073ad22c62SMaxim Patlasov arg->ctime = iattr->ia_ctime.tv_sec; 15083ad22c62SMaxim Patlasov arg->ctimensec = iattr->ia_ctime.tv_nsec; 15093ad22c62SMaxim Patlasov } 15109e6268dbSMiklos Szeredi } 15119e6268dbSMiklos Szeredi 15126f9f1180SMiklos Szeredi /* 15133be5a52bSMiklos Szeredi * Prevent concurrent writepages on inode 15143be5a52bSMiklos Szeredi * 15153be5a52bSMiklos Szeredi * This is done by adding a negative bias to the inode write counter 15163be5a52bSMiklos Szeredi * and waiting for all pending writes to finish. 15173be5a52bSMiklos Szeredi */ 15183be5a52bSMiklos Szeredi void fuse_set_nowrite(struct inode *inode) 15193be5a52bSMiklos Szeredi { 15203be5a52bSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 15213be5a52bSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 15223be5a52bSMiklos Szeredi 15235955102cSAl Viro BUG_ON(!inode_is_locked(inode)); 15243be5a52bSMiklos Szeredi 15253be5a52bSMiklos Szeredi spin_lock(&fc->lock); 15263be5a52bSMiklos Szeredi BUG_ON(fi->writectr < 0); 15273be5a52bSMiklos Szeredi fi->writectr += FUSE_NOWRITE; 15283be5a52bSMiklos Szeredi spin_unlock(&fc->lock); 15293be5a52bSMiklos Szeredi wait_event(fi->page_waitq, fi->writectr == FUSE_NOWRITE); 15303be5a52bSMiklos Szeredi } 15313be5a52bSMiklos Szeredi 15323be5a52bSMiklos Szeredi /* 15333be5a52bSMiklos Szeredi * Allow writepages on inode 15343be5a52bSMiklos Szeredi * 15353be5a52bSMiklos Szeredi * Remove the bias from the writecounter and send any queued 15363be5a52bSMiklos Szeredi * writepages. 15373be5a52bSMiklos Szeredi */ 15383be5a52bSMiklos Szeredi static void __fuse_release_nowrite(struct inode *inode) 15393be5a52bSMiklos Szeredi { 15403be5a52bSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 15413be5a52bSMiklos Szeredi 15423be5a52bSMiklos Szeredi BUG_ON(fi->writectr != FUSE_NOWRITE); 15433be5a52bSMiklos Szeredi fi->writectr = 0; 15443be5a52bSMiklos Szeredi fuse_flush_writepages(inode); 15453be5a52bSMiklos Szeredi } 15463be5a52bSMiklos Szeredi 15473be5a52bSMiklos Szeredi void fuse_release_nowrite(struct inode *inode) 15483be5a52bSMiklos Szeredi { 15493be5a52bSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 15503be5a52bSMiklos Szeredi 15513be5a52bSMiklos Szeredi spin_lock(&fc->lock); 15523be5a52bSMiklos Szeredi __fuse_release_nowrite(inode); 15533be5a52bSMiklos Szeredi spin_unlock(&fc->lock); 15543be5a52bSMiklos Szeredi } 15553be5a52bSMiklos Szeredi 15567078187aSMiklos Szeredi static void fuse_setattr_fill(struct fuse_conn *fc, struct fuse_args *args, 1557b0aa7606SMaxim Patlasov struct inode *inode, 1558b0aa7606SMaxim Patlasov struct fuse_setattr_in *inarg_p, 1559b0aa7606SMaxim Patlasov struct fuse_attr_out *outarg_p) 1560b0aa7606SMaxim Patlasov { 15617078187aSMiklos Szeredi args->in.h.opcode = FUSE_SETATTR; 15627078187aSMiklos Szeredi args->in.h.nodeid = get_node_id(inode); 15637078187aSMiklos Szeredi args->in.numargs = 1; 15647078187aSMiklos Szeredi args->in.args[0].size = sizeof(*inarg_p); 15657078187aSMiklos Szeredi args->in.args[0].value = inarg_p; 15667078187aSMiklos Szeredi args->out.numargs = 1; 15677078187aSMiklos Szeredi args->out.args[0].size = sizeof(*outarg_p); 15687078187aSMiklos Szeredi args->out.args[0].value = outarg_p; 1569b0aa7606SMaxim Patlasov } 1570b0aa7606SMaxim Patlasov 1571b0aa7606SMaxim Patlasov /* 1572b0aa7606SMaxim Patlasov * Flush inode->i_mtime to the server 1573b0aa7606SMaxim Patlasov */ 1574ab9e13f7SMaxim Patlasov int fuse_flush_times(struct inode *inode, struct fuse_file *ff) 1575b0aa7606SMaxim Patlasov { 1576b0aa7606SMaxim Patlasov struct fuse_conn *fc = get_fuse_conn(inode); 15777078187aSMiklos Szeredi FUSE_ARGS(args); 1578b0aa7606SMaxim Patlasov struct fuse_setattr_in inarg; 1579b0aa7606SMaxim Patlasov struct fuse_attr_out outarg; 1580b0aa7606SMaxim Patlasov 1581b0aa7606SMaxim Patlasov memset(&inarg, 0, sizeof(inarg)); 1582b0aa7606SMaxim Patlasov memset(&outarg, 0, sizeof(outarg)); 1583b0aa7606SMaxim Patlasov 1584ab9e13f7SMaxim Patlasov inarg.valid = FATTR_MTIME; 1585b0aa7606SMaxim Patlasov inarg.mtime = inode->i_mtime.tv_sec; 1586b0aa7606SMaxim Patlasov inarg.mtimensec = inode->i_mtime.tv_nsec; 1587ab9e13f7SMaxim Patlasov if (fc->minor >= 23) { 1588ab9e13f7SMaxim Patlasov inarg.valid |= FATTR_CTIME; 1589ab9e13f7SMaxim Patlasov inarg.ctime = inode->i_ctime.tv_sec; 1590ab9e13f7SMaxim Patlasov inarg.ctimensec = inode->i_ctime.tv_nsec; 1591ab9e13f7SMaxim Patlasov } 15921e18bda8SMiklos Szeredi if (ff) { 15931e18bda8SMiklos Szeredi inarg.valid |= FATTR_FH; 15941e18bda8SMiklos Szeredi inarg.fh = ff->fh; 15951e18bda8SMiklos Szeredi } 15967078187aSMiklos Szeredi fuse_setattr_fill(fc, &args, inode, &inarg, &outarg); 1597b0aa7606SMaxim Patlasov 15987078187aSMiklos Szeredi return fuse_simple_request(fc, &args); 1599b0aa7606SMaxim Patlasov } 1600b0aa7606SMaxim Patlasov 16013be5a52bSMiklos Szeredi /* 16026f9f1180SMiklos Szeredi * Set attributes, and at the same time refresh them. 16036f9f1180SMiklos Szeredi * 16046f9f1180SMiklos Szeredi * Truncation is slightly complicated, because the 'truncate' request 16056f9f1180SMiklos Szeredi * may fail, in which case we don't want to touch the mapping. 16069ffbb916SMiklos Szeredi * vmtruncate() doesn't allow for this case, so do the rlimit checking 16079ffbb916SMiklos Szeredi * and the actual truncation by hand. 16086f9f1180SMiklos Szeredi */ 160962490330SJan Kara int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, 161049d4914fSMiklos Szeredi struct file *file) 16119e6268dbSMiklos Szeredi { 161262490330SJan Kara struct inode *inode = d_inode(dentry); 16139e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 161406a7c3c2SMaxim Patlasov struct fuse_inode *fi = get_fuse_inode(inode); 16157078187aSMiklos Szeredi FUSE_ARGS(args); 16169e6268dbSMiklos Szeredi struct fuse_setattr_in inarg; 16179e6268dbSMiklos Szeredi struct fuse_attr_out outarg; 16183be5a52bSMiklos Szeredi bool is_truncate = false; 16198373200bSPavel Emelyanov bool is_wb = fc->writeback_cache; 16203be5a52bSMiklos Szeredi loff_t oldsize; 16219e6268dbSMiklos Szeredi int err; 16223ad22c62SMaxim Patlasov bool trust_local_cmtime = is_wb && S_ISREG(inode->i_mode); 16239e6268dbSMiklos Szeredi 162429433a29SMiklos Szeredi if (!fc->default_permissions) 1625db78b877SChristoph Hellwig attr->ia_valid |= ATTR_FORCE; 1626db78b877SChristoph Hellwig 162731051c85SJan Kara err = setattr_prepare(dentry, attr); 16281e9a4ed9SMiklos Szeredi if (err) 16291e9a4ed9SMiklos Szeredi return err; 16301e9a4ed9SMiklos Szeredi 16318d56adddSMiklos Szeredi if (attr->ia_valid & ATTR_OPEN) { 16328d56adddSMiklos Szeredi if (fc->atomic_o_trunc) 16336ff958edSMiklos Szeredi return 0; 16348d56adddSMiklos Szeredi file = NULL; 16358d56adddSMiklos Szeredi } 16366ff958edSMiklos Szeredi 16372c27c65eSChristoph Hellwig if (attr->ia_valid & ATTR_SIZE) 16383be5a52bSMiklos Szeredi is_truncate = true; 16399e6268dbSMiklos Szeredi 164006a7c3c2SMaxim Patlasov if (is_truncate) { 16413be5a52bSMiklos Szeredi fuse_set_nowrite(inode); 164206a7c3c2SMaxim Patlasov set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); 16433ad22c62SMaxim Patlasov if (trust_local_cmtime && attr->ia_size != inode->i_size) 16443ad22c62SMaxim Patlasov attr->ia_valid |= ATTR_MTIME | ATTR_CTIME; 164506a7c3c2SMaxim Patlasov } 16463be5a52bSMiklos Szeredi 16479e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 16480e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 16493ad22c62SMaxim Patlasov iattr_to_fattr(attr, &inarg, trust_local_cmtime); 165049d4914fSMiklos Szeredi if (file) { 165149d4914fSMiklos Szeredi struct fuse_file *ff = file->private_data; 165249d4914fSMiklos Szeredi inarg.valid |= FATTR_FH; 165349d4914fSMiklos Szeredi inarg.fh = ff->fh; 165449d4914fSMiklos Szeredi } 1655f3332114SMiklos Szeredi if (attr->ia_valid & ATTR_SIZE) { 1656f3332114SMiklos Szeredi /* For mandatory locking in truncate */ 1657f3332114SMiklos Szeredi inarg.valid |= FATTR_LOCKOWNER; 1658f3332114SMiklos Szeredi inarg.lock_owner = fuse_lock_owner_id(fc, current->files); 1659f3332114SMiklos Szeredi } 16607078187aSMiklos Szeredi fuse_setattr_fill(fc, &args, inode, &inarg, &outarg); 16617078187aSMiklos Szeredi err = fuse_simple_request(fc, &args); 1662e00d2c2dSMiklos Szeredi if (err) { 1663e00d2c2dSMiklos Szeredi if (err == -EINTR) 1664e00d2c2dSMiklos Szeredi fuse_invalidate_attr(inode); 16653be5a52bSMiklos Szeredi goto error; 1666e00d2c2dSMiklos Szeredi } 1667e00d2c2dSMiklos Szeredi 16689e6268dbSMiklos Szeredi if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { 16699e6268dbSMiklos Szeredi make_bad_inode(inode); 16703be5a52bSMiklos Szeredi err = -EIO; 16713be5a52bSMiklos Szeredi goto error; 16729e6268dbSMiklos Szeredi } 16739e6268dbSMiklos Szeredi 16743be5a52bSMiklos Szeredi spin_lock(&fc->lock); 1675b0aa7606SMaxim Patlasov /* the kernel maintains i_mtime locally */ 16763ad22c62SMaxim Patlasov if (trust_local_cmtime) { 16773ad22c62SMaxim Patlasov if (attr->ia_valid & ATTR_MTIME) 1678b0aa7606SMaxim Patlasov inode->i_mtime = attr->ia_mtime; 16793ad22c62SMaxim Patlasov if (attr->ia_valid & ATTR_CTIME) 16803ad22c62SMaxim Patlasov inode->i_ctime = attr->ia_ctime; 16811e18bda8SMiklos Szeredi /* FIXME: clear I_DIRTY_SYNC? */ 1682b0aa7606SMaxim Patlasov } 1683b0aa7606SMaxim Patlasov 16843be5a52bSMiklos Szeredi fuse_change_attributes_common(inode, &outarg.attr, 16853be5a52bSMiklos Szeredi attr_timeout(&outarg)); 16863be5a52bSMiklos Szeredi oldsize = inode->i_size; 16878373200bSPavel Emelyanov /* see the comment in fuse_change_attributes() */ 16888373200bSPavel Emelyanov if (!is_wb || is_truncate || !S_ISREG(inode->i_mode)) 16893be5a52bSMiklos Szeredi i_size_write(inode, outarg.attr.size); 16903be5a52bSMiklos Szeredi 16913be5a52bSMiklos Szeredi if (is_truncate) { 16923be5a52bSMiklos Szeredi /* NOTE: this may release/reacquire fc->lock */ 16933be5a52bSMiklos Szeredi __fuse_release_nowrite(inode); 16943be5a52bSMiklos Szeredi } 16953be5a52bSMiklos Szeredi spin_unlock(&fc->lock); 16963be5a52bSMiklos Szeredi 16973be5a52bSMiklos Szeredi /* 16983be5a52bSMiklos Szeredi * Only call invalidate_inode_pages2() after removing 16993be5a52bSMiklos Szeredi * FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock. 17003be5a52bSMiklos Szeredi */ 17018373200bSPavel Emelyanov if ((is_truncate || !is_wb) && 17028373200bSPavel Emelyanov S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) { 17037caef267SKirill A. Shutemov truncate_pagecache(inode, outarg.attr.size); 17043be5a52bSMiklos Szeredi invalidate_inode_pages2(inode->i_mapping); 17053be5a52bSMiklos Szeredi } 17063be5a52bSMiklos Szeredi 170706a7c3c2SMaxim Patlasov clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); 1708e00d2c2dSMiklos Szeredi return 0; 17093be5a52bSMiklos Szeredi 17103be5a52bSMiklos Szeredi error: 17113be5a52bSMiklos Szeredi if (is_truncate) 17123be5a52bSMiklos Szeredi fuse_release_nowrite(inode); 17133be5a52bSMiklos Szeredi 171406a7c3c2SMaxim Patlasov clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); 17153be5a52bSMiklos Szeredi return err; 17169e6268dbSMiklos Szeredi } 17179e6268dbSMiklos Szeredi 171849d4914fSMiklos Szeredi static int fuse_setattr(struct dentry *entry, struct iattr *attr) 171949d4914fSMiklos Szeredi { 17202b0143b5SDavid Howells struct inode *inode = d_inode(entry); 17215e940c1dSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1722a09f99edSMiklos Szeredi struct file *file = (attr->ia_valid & ATTR_FILE) ? attr->ia_file : NULL; 17235e2b8828SMiklos Szeredi int ret; 1724efb9fa9eSMaxim Patlasov 1725efb9fa9eSMaxim Patlasov if (!fuse_allow_current_process(get_fuse_conn(inode))) 1726efb9fa9eSMaxim Patlasov return -EACCES; 1727efb9fa9eSMaxim Patlasov 1728a09f99edSMiklos Szeredi if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) { 1729a09f99edSMiklos Szeredi attr->ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | 1730a09f99edSMiklos Szeredi ATTR_MODE); 17315e940c1dSMiklos Szeredi 1732a09f99edSMiklos Szeredi /* 17335e940c1dSMiklos Szeredi * The only sane way to reliably kill suid/sgid is to do it in 17345e940c1dSMiklos Szeredi * the userspace filesystem 17355e940c1dSMiklos Szeredi * 17365e940c1dSMiklos Szeredi * This should be done on write(), truncate() and chown(). 17375e940c1dSMiklos Szeredi */ 17385e940c1dSMiklos Szeredi if (!fc->handle_killpriv) { 17395e940c1dSMiklos Szeredi /* 17405e940c1dSMiklos Szeredi * ia_mode calculation may have used stale i_mode. 17415e940c1dSMiklos Szeredi * Refresh and recalculate. 1742a09f99edSMiklos Szeredi */ 1743a09f99edSMiklos Szeredi ret = fuse_do_getattr(inode, NULL, file); 1744a09f99edSMiklos Szeredi if (ret) 1745a09f99edSMiklos Szeredi return ret; 1746a09f99edSMiklos Szeredi 1747a09f99edSMiklos Szeredi attr->ia_mode = inode->i_mode; 1748c01638f5SMiklos Szeredi if (inode->i_mode & S_ISUID) { 1749a09f99edSMiklos Szeredi attr->ia_valid |= ATTR_MODE; 1750a09f99edSMiklos Szeredi attr->ia_mode &= ~S_ISUID; 1751a09f99edSMiklos Szeredi } 1752c01638f5SMiklos Szeredi if ((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { 1753a09f99edSMiklos Szeredi attr->ia_valid |= ATTR_MODE; 1754a09f99edSMiklos Szeredi attr->ia_mode &= ~S_ISGID; 1755a09f99edSMiklos Szeredi } 1756a09f99edSMiklos Szeredi } 17575e940c1dSMiklos Szeredi } 1758a09f99edSMiklos Szeredi if (!attr->ia_valid) 1759a09f99edSMiklos Szeredi return 0; 1760a09f99edSMiklos Szeredi 1761abb5a14fSLinus Torvalds ret = fuse_do_setattr(entry, attr, file); 17625e2b8828SMiklos Szeredi if (!ret) { 176360bcc88aSSeth Forshee /* 176460bcc88aSSeth Forshee * If filesystem supports acls it may have updated acl xattrs in 176560bcc88aSSeth Forshee * the filesystem, so forget cached acls for the inode. 176660bcc88aSSeth Forshee */ 176760bcc88aSSeth Forshee if (fc->posix_acl) 176860bcc88aSSeth Forshee forget_all_cached_acls(inode); 176960bcc88aSSeth Forshee 17705e2b8828SMiklos Szeredi /* Directory mode changed, may need to revalidate access */ 17715e2b8828SMiklos Szeredi if (d_is_dir(entry) && (attr->ia_valid & ATTR_MODE)) 17725e2b8828SMiklos Szeredi fuse_invalidate_entry_cache(entry); 17735e2b8828SMiklos Szeredi } 17745e2b8828SMiklos Szeredi return ret; 177549d4914fSMiklos Szeredi } 177649d4914fSMiklos Szeredi 1777a528d35eSDavid Howells static int fuse_getattr(const struct path *path, struct kstat *stat, 1778a528d35eSDavid Howells u32 request_mask, unsigned int flags) 1779e5e5558eSMiklos Szeredi { 1780a528d35eSDavid Howells struct inode *inode = d_inode(path->dentry); 1781244f6385SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1782244f6385SMiklos Szeredi 1783c2132c1bSAnatol Pomozov if (!fuse_allow_current_process(fc)) 1784244f6385SMiklos Szeredi return -EACCES; 1785244f6385SMiklos Szeredi 17865b97eeacSMiklos Szeredi return fuse_update_get_attr(inode, NULL, stat); 1787e5e5558eSMiklos Szeredi } 1788e5e5558eSMiklos Szeredi 1789754661f1SArjan van de Ven static const struct inode_operations fuse_dir_inode_operations = { 1790e5e5558eSMiklos Szeredi .lookup = fuse_lookup, 17919e6268dbSMiklos Szeredi .mkdir = fuse_mkdir, 17929e6268dbSMiklos Szeredi .symlink = fuse_symlink, 17939e6268dbSMiklos Szeredi .unlink = fuse_unlink, 17949e6268dbSMiklos Szeredi .rmdir = fuse_rmdir, 17952773bf00SMiklos Szeredi .rename = fuse_rename2, 17969e6268dbSMiklos Szeredi .link = fuse_link, 17979e6268dbSMiklos Szeredi .setattr = fuse_setattr, 17989e6268dbSMiklos Szeredi .create = fuse_create, 1799c8ccbe03SMiklos Szeredi .atomic_open = fuse_atomic_open, 18009e6268dbSMiklos Szeredi .mknod = fuse_mknod, 1801e5e5558eSMiklos Szeredi .permission = fuse_permission, 1802e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 180392a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 180460bcc88aSSeth Forshee .get_acl = fuse_get_acl, 180560bcc88aSSeth Forshee .set_acl = fuse_set_acl, 1806e5e5558eSMiklos Szeredi }; 1807e5e5558eSMiklos Szeredi 18084b6f5d20SArjan van de Ven static const struct file_operations fuse_dir_operations = { 1809b6aeadedSMiklos Szeredi .llseek = generic_file_llseek, 1810e5e5558eSMiklos Szeredi .read = generic_read_dir, 1811d9b3dbdcSAl Viro .iterate_shared = fuse_readdir, 1812e5e5558eSMiklos Szeredi .open = fuse_dir_open, 1813e5e5558eSMiklos Szeredi .release = fuse_dir_release, 181482547981SMiklos Szeredi .fsync = fuse_dir_fsync, 1815b18da0c5SMiklos Szeredi .unlocked_ioctl = fuse_dir_ioctl, 1816b18da0c5SMiklos Szeredi .compat_ioctl = fuse_dir_compat_ioctl, 1817e5e5558eSMiklos Szeredi }; 1818e5e5558eSMiklos Szeredi 1819754661f1SArjan van de Ven static const struct inode_operations fuse_common_inode_operations = { 18209e6268dbSMiklos Szeredi .setattr = fuse_setattr, 1821e5e5558eSMiklos Szeredi .permission = fuse_permission, 1822e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 182392a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 182460bcc88aSSeth Forshee .get_acl = fuse_get_acl, 182560bcc88aSSeth Forshee .set_acl = fuse_set_acl, 1826e5e5558eSMiklos Szeredi }; 1827e5e5558eSMiklos Szeredi 1828754661f1SArjan van de Ven static const struct inode_operations fuse_symlink_inode_operations = { 18299e6268dbSMiklos Szeredi .setattr = fuse_setattr, 18306b255391SAl Viro .get_link = fuse_get_link, 1831e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 183292a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 1833e5e5558eSMiklos Szeredi }; 1834e5e5558eSMiklos Szeredi 1835e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode) 1836e5e5558eSMiklos Szeredi { 1837e5e5558eSMiklos Szeredi inode->i_op = &fuse_common_inode_operations; 1838e5e5558eSMiklos Szeredi } 1839e5e5558eSMiklos Szeredi 1840e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode) 1841e5e5558eSMiklos Szeredi { 1842e5e5558eSMiklos Szeredi inode->i_op = &fuse_dir_inode_operations; 1843e5e5558eSMiklos Szeredi inode->i_fop = &fuse_dir_operations; 1844e5e5558eSMiklos Szeredi } 1845e5e5558eSMiklos Szeredi 1846e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode) 1847e5e5558eSMiklos Szeredi { 1848e5e5558eSMiklos Szeredi inode->i_op = &fuse_symlink_inode_operations; 1849e5e5558eSMiklos Szeredi } 1850