1e5e5558eSMiklos Szeredi /* 2e5e5558eSMiklos Szeredi FUSE: Filesystem in Userspace 351eb01e7SMiklos Szeredi Copyright (C) 2001-2006 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/gfp.h> 14e5e5558eSMiklos Szeredi #include <linux/sched.h> 15e5e5558eSMiklos Szeredi #include <linux/namei.h> 16e5e5558eSMiklos Szeredi 170a0898cfSMiklos Szeredi #if BITS_PER_LONG >= 64 180a0898cfSMiklos Szeredi static inline void fuse_dentry_settime(struct dentry *entry, u64 time) 190a0898cfSMiklos Szeredi { 200a0898cfSMiklos Szeredi entry->d_time = time; 210a0898cfSMiklos Szeredi } 220a0898cfSMiklos Szeredi 230a0898cfSMiklos Szeredi static inline u64 fuse_dentry_time(struct dentry *entry) 240a0898cfSMiklos Szeredi { 250a0898cfSMiklos Szeredi return entry->d_time; 260a0898cfSMiklos Szeredi } 270a0898cfSMiklos Szeredi #else 280a0898cfSMiklos Szeredi /* 290a0898cfSMiklos Szeredi * On 32 bit archs store the high 32 bits of time in d_fsdata 300a0898cfSMiklos Szeredi */ 310a0898cfSMiklos Szeredi static void fuse_dentry_settime(struct dentry *entry, u64 time) 320a0898cfSMiklos Szeredi { 330a0898cfSMiklos Szeredi entry->d_time = time; 340a0898cfSMiklos Szeredi entry->d_fsdata = (void *) (unsigned long) (time >> 32); 350a0898cfSMiklos Szeredi } 360a0898cfSMiklos Szeredi 370a0898cfSMiklos Szeredi static u64 fuse_dentry_time(struct dentry *entry) 380a0898cfSMiklos Szeredi { 390a0898cfSMiklos Szeredi return (u64) entry->d_time + 400a0898cfSMiklos Szeredi ((u64) (unsigned long) entry->d_fsdata << 32); 410a0898cfSMiklos Szeredi } 420a0898cfSMiklos Szeredi #endif 430a0898cfSMiklos Szeredi 446f9f1180SMiklos Szeredi /* 456f9f1180SMiklos Szeredi * FUSE caches dentries and attributes with separate timeout. The 466f9f1180SMiklos Szeredi * time in jiffies until the dentry/attributes are valid is stored in 476f9f1180SMiklos Szeredi * dentry->d_time and fuse_inode->i_time respectively. 486f9f1180SMiklos Szeredi */ 496f9f1180SMiklos Szeredi 506f9f1180SMiklos Szeredi /* 516f9f1180SMiklos Szeredi * Calculate the time in jiffies until a dentry/attributes are valid 526f9f1180SMiklos Szeredi */ 530a0898cfSMiklos Szeredi static u64 time_to_jiffies(unsigned long sec, unsigned long nsec) 54e5e5558eSMiklos Szeredi { 55685d16ddSMiklos Szeredi if (sec || nsec) { 56e5e5558eSMiklos Szeredi struct timespec ts = {sec, nsec}; 570a0898cfSMiklos Szeredi return get_jiffies_64() + timespec_to_jiffies(&ts); 58685d16ddSMiklos Szeredi } else 590a0898cfSMiklos Szeredi return 0; 60e5e5558eSMiklos Szeredi } 61e5e5558eSMiklos Szeredi 626f9f1180SMiklos Szeredi /* 636f9f1180SMiklos Szeredi * Set dentry and possibly attribute timeouts from the lookup/mk* 646f9f1180SMiklos Szeredi * replies 656f9f1180SMiklos Szeredi */ 661fb69e78SMiklos Szeredi static void fuse_change_entry_timeout(struct dentry *entry, 671fb69e78SMiklos Szeredi struct fuse_entry_out *o) 680aa7c699SMiklos Szeredi { 690a0898cfSMiklos Szeredi fuse_dentry_settime(entry, 700a0898cfSMiklos Szeredi time_to_jiffies(o->entry_valid, o->entry_valid_nsec)); 711fb69e78SMiklos Szeredi } 721fb69e78SMiklos Szeredi 731fb69e78SMiklos Szeredi static u64 attr_timeout(struct fuse_attr_out *o) 741fb69e78SMiklos Szeredi { 751fb69e78SMiklos Szeredi return time_to_jiffies(o->attr_valid, o->attr_valid_nsec); 761fb69e78SMiklos Szeredi } 771fb69e78SMiklos Szeredi 781fb69e78SMiklos Szeredi static u64 entry_attr_timeout(struct fuse_entry_out *o) 791fb69e78SMiklos Szeredi { 801fb69e78SMiklos Szeredi return time_to_jiffies(o->attr_valid, o->attr_valid_nsec); 818cbdf1e6SMiklos Szeredi } 828cbdf1e6SMiklos Szeredi 836f9f1180SMiklos Szeredi /* 846f9f1180SMiklos Szeredi * Mark the attributes as stale, so that at the next call to 856f9f1180SMiklos Szeredi * ->getattr() they will be fetched from userspace 866f9f1180SMiklos Szeredi */ 878cbdf1e6SMiklos Szeredi void fuse_invalidate_attr(struct inode *inode) 888cbdf1e6SMiklos Szeredi { 890a0898cfSMiklos Szeredi get_fuse_inode(inode)->i_time = 0; 908cbdf1e6SMiklos Szeredi } 918cbdf1e6SMiklos Szeredi 926f9f1180SMiklos Szeredi /* 936f9f1180SMiklos Szeredi * Just mark the entry as stale, so that a next attempt to look it up 946f9f1180SMiklos Szeredi * will result in a new lookup call to userspace 956f9f1180SMiklos Szeredi * 966f9f1180SMiklos Szeredi * This is called when a dentry is about to become negative and the 976f9f1180SMiklos Szeredi * timeout is unknown (unlink, rmdir, rename and in some cases 986f9f1180SMiklos Szeredi * lookup) 996f9f1180SMiklos Szeredi */ 1008cbdf1e6SMiklos Szeredi static void fuse_invalidate_entry_cache(struct dentry *entry) 1018cbdf1e6SMiklos Szeredi { 1020a0898cfSMiklos Szeredi fuse_dentry_settime(entry, 0); 1038cbdf1e6SMiklos Szeredi } 1048cbdf1e6SMiklos Szeredi 1056f9f1180SMiklos Szeredi /* 1066f9f1180SMiklos Szeredi * Same as fuse_invalidate_entry_cache(), but also try to remove the 1076f9f1180SMiklos Szeredi * dentry from the hash 1086f9f1180SMiklos Szeredi */ 1098cbdf1e6SMiklos Szeredi static void fuse_invalidate_entry(struct dentry *entry) 1108cbdf1e6SMiklos Szeredi { 1118cbdf1e6SMiklos Szeredi d_invalidate(entry); 1128cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 1130aa7c699SMiklos Szeredi } 1140aa7c699SMiklos Szeredi 115e5e5558eSMiklos Szeredi static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, 116e5e5558eSMiklos Szeredi struct dentry *entry, 117e5e5558eSMiklos Szeredi struct fuse_entry_out *outarg) 118e5e5558eSMiklos Szeredi { 1190e9663eeSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 1200e9663eeSMiklos Szeredi 1210e9663eeSMiklos Szeredi memset(outarg, 0, sizeof(struct fuse_entry_out)); 122e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_LOOKUP; 123e5e5558eSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 124e5e5558eSMiklos Szeredi req->in.numargs = 1; 125e5e5558eSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 126e5e5558eSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 127e5e5558eSMiklos Szeredi req->out.numargs = 1; 1280e9663eeSMiklos Szeredi if (fc->minor < 9) 1290e9663eeSMiklos Szeredi req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; 1300e9663eeSMiklos Szeredi else 131e5e5558eSMiklos Szeredi req->out.args[0].size = sizeof(struct fuse_entry_out); 132e5e5558eSMiklos Szeredi req->out.args[0].value = outarg; 133e5e5558eSMiklos Szeredi } 134e5e5558eSMiklos Szeredi 1357dca9fd3SMiklos Szeredi static u64 fuse_get_attr_version(struct fuse_conn *fc) 1367dca9fd3SMiklos Szeredi { 1377dca9fd3SMiklos Szeredi u64 curr_version; 1387dca9fd3SMiklos Szeredi 1397dca9fd3SMiklos Szeredi /* 1407dca9fd3SMiklos Szeredi * The spin lock isn't actually needed on 64bit archs, but we 1417dca9fd3SMiklos Szeredi * don't yet care too much about such optimizations. 1427dca9fd3SMiklos Szeredi */ 1437dca9fd3SMiklos Szeredi spin_lock(&fc->lock); 1447dca9fd3SMiklos Szeredi curr_version = fc->attr_version; 1457dca9fd3SMiklos Szeredi spin_unlock(&fc->lock); 1467dca9fd3SMiklos Szeredi 1477dca9fd3SMiklos Szeredi return curr_version; 1487dca9fd3SMiklos Szeredi } 1497dca9fd3SMiklos Szeredi 1506f9f1180SMiklos Szeredi /* 1516f9f1180SMiklos Szeredi * Check whether the dentry is still valid 1526f9f1180SMiklos Szeredi * 1536f9f1180SMiklos Szeredi * If the entry validity timeout has expired and the dentry is 1546f9f1180SMiklos Szeredi * positive, try to redo the lookup. If the lookup results in a 1556f9f1180SMiklos Szeredi * different inode, then let the VFS invalidate the dentry and redo 1566f9f1180SMiklos Szeredi * the lookup once more. If the lookup results in the same inode, 1576f9f1180SMiklos Szeredi * then refresh the attributes, timeouts and mark the dentry valid. 1586f9f1180SMiklos Szeredi */ 159e5e5558eSMiklos Szeredi static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) 160e5e5558eSMiklos Szeredi { 1618cbdf1e6SMiklos Szeredi struct inode *inode = entry->d_inode; 1628cbdf1e6SMiklos Szeredi 1638cbdf1e6SMiklos Szeredi if (inode && is_bad_inode(inode)) 164e5e5558eSMiklos Szeredi return 0; 1650a0898cfSMiklos Szeredi else if (fuse_dentry_time(entry) < get_jiffies_64()) { 166e5e5558eSMiklos Szeredi int err; 167e5e5558eSMiklos Szeredi struct fuse_entry_out outarg; 1688cbdf1e6SMiklos Szeredi struct fuse_conn *fc; 1698cbdf1e6SMiklos Szeredi struct fuse_req *req; 1702d51013eSMiklos Szeredi struct fuse_req *forget_req; 171e956edd0SMiklos Szeredi struct dentry *parent; 1721fb69e78SMiklos Szeredi u64 attr_version; 1738cbdf1e6SMiklos Szeredi 17450322fe7SMiklos Szeredi /* For negative dentries, always do a fresh lookup */ 1758cbdf1e6SMiklos Szeredi if (!inode) 1768cbdf1e6SMiklos Szeredi return 0; 1778cbdf1e6SMiklos Szeredi 1788cbdf1e6SMiklos Szeredi fc = get_fuse_conn(inode); 179ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 180ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 181e5e5558eSMiklos Szeredi return 0; 182e5e5558eSMiklos Szeredi 1832d51013eSMiklos Szeredi forget_req = fuse_get_req(fc); 1842d51013eSMiklos Szeredi if (IS_ERR(forget_req)) { 1852d51013eSMiklos Szeredi fuse_put_request(fc, req); 1862d51013eSMiklos Szeredi return 0; 1872d51013eSMiklos Szeredi } 1882d51013eSMiklos Szeredi 1897dca9fd3SMiklos Szeredi attr_version = fuse_get_attr_version(fc); 1901fb69e78SMiklos Szeredi 191e956edd0SMiklos Szeredi parent = dget_parent(entry); 192e956edd0SMiklos Szeredi fuse_lookup_init(req, parent->d_inode, entry, &outarg); 1937c352bdfSMiklos Szeredi request_send(fc, req); 194e956edd0SMiklos Szeredi dput(parent); 195e5e5558eSMiklos Szeredi err = req->out.h.error; 1962d51013eSMiklos Szeredi fuse_put_request(fc, req); 19750322fe7SMiklos Szeredi /* Zero nodeid is same as -ENOENT */ 19850322fe7SMiklos Szeredi if (!err && !outarg.nodeid) 19950322fe7SMiklos Szeredi err = -ENOENT; 2009e6268dbSMiklos Szeredi if (!err) { 2018cbdf1e6SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 2029e6268dbSMiklos Szeredi if (outarg.nodeid != get_node_id(inode)) { 2032d51013eSMiklos Szeredi fuse_send_forget(fc, forget_req, 2042d51013eSMiklos Szeredi outarg.nodeid, 1); 2059e6268dbSMiklos Szeredi return 0; 2069e6268dbSMiklos Szeredi } 2078da5ff23SMiklos Szeredi spin_lock(&fc->lock); 2089e6268dbSMiklos Szeredi fi->nlookup ++; 2098da5ff23SMiklos Szeredi spin_unlock(&fc->lock); 2109e6268dbSMiklos Szeredi } 2112d51013eSMiklos Szeredi fuse_put_request(fc, forget_req); 2129e6268dbSMiklos Szeredi if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) 213e5e5558eSMiklos Szeredi return 0; 214e5e5558eSMiklos Szeredi 2151fb69e78SMiklos Szeredi fuse_change_attributes(inode, &outarg.attr, 2161fb69e78SMiklos Szeredi entry_attr_timeout(&outarg), 2171fb69e78SMiklos Szeredi attr_version); 2181fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outarg); 219e5e5558eSMiklos Szeredi } 220e5e5558eSMiklos Szeredi return 1; 221e5e5558eSMiklos Szeredi } 222e5e5558eSMiklos Szeredi 2238bfc016dSMiklos Szeredi static int invalid_nodeid(u64 nodeid) 2242827d0b2SMiklos Szeredi { 2252827d0b2SMiklos Szeredi return !nodeid || nodeid == FUSE_ROOT_ID; 2262827d0b2SMiklos Szeredi } 2272827d0b2SMiklos Szeredi 228e5e5558eSMiklos Szeredi static struct dentry_operations fuse_dentry_operations = { 229e5e5558eSMiklos Szeredi .d_revalidate = fuse_dentry_revalidate, 230e5e5558eSMiklos Szeredi }; 231e5e5558eSMiklos Szeredi 232a5bfffacSTimo Savola int fuse_valid_type(int m) 23339ee059aSMiklos Szeredi { 23439ee059aSMiklos Szeredi return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) || 23539ee059aSMiklos Szeredi S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); 23639ee059aSMiklos Szeredi } 23739ee059aSMiklos Szeredi 238d2a85164SMiklos Szeredi /* 239d2a85164SMiklos Szeredi * Add a directory inode to a dentry, ensuring that no other dentry 240d2a85164SMiklos Szeredi * refers to this inode. Called with fc->inst_mutex. 241d2a85164SMiklos Szeredi */ 242d2a85164SMiklos Szeredi static int fuse_d_add_directory(struct dentry *entry, struct inode *inode) 243d2a85164SMiklos Szeredi { 244d2a85164SMiklos Szeredi struct dentry *alias = d_find_alias(inode); 245d2a85164SMiklos Szeredi if (alias) { 246d2a85164SMiklos Szeredi /* This tries to shrink the subtree below alias */ 247d2a85164SMiklos Szeredi fuse_invalidate_entry(alias); 248d2a85164SMiklos Szeredi dput(alias); 249d2a85164SMiklos Szeredi if (!list_empty(&inode->i_dentry)) 250d2a85164SMiklos Szeredi return -EBUSY; 251d2a85164SMiklos Szeredi } 252d2a85164SMiklos Szeredi d_add(entry, inode); 253d2a85164SMiklos Szeredi return 0; 254d2a85164SMiklos Szeredi } 255d2a85164SMiklos Szeredi 2560aa7c699SMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, 2570aa7c699SMiklos Szeredi struct nameidata *nd) 258e5e5558eSMiklos Szeredi { 259e5e5558eSMiklos Szeredi int err; 260e5e5558eSMiklos Szeredi struct fuse_entry_out outarg; 261e5e5558eSMiklos Szeredi struct inode *inode = NULL; 262e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 263e5e5558eSMiklos Szeredi struct fuse_req *req; 2642d51013eSMiklos Szeredi struct fuse_req *forget_req; 2651fb69e78SMiklos Szeredi u64 attr_version; 266e5e5558eSMiklos Szeredi 267e5e5558eSMiklos Szeredi if (entry->d_name.len > FUSE_NAME_MAX) 2680aa7c699SMiklos Szeredi return ERR_PTR(-ENAMETOOLONG); 269e5e5558eSMiklos Szeredi 270ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 271ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 272ce1d5a49SMiklos Szeredi return ERR_PTR(PTR_ERR(req)); 273e5e5558eSMiklos Szeredi 2742d51013eSMiklos Szeredi forget_req = fuse_get_req(fc); 2752d51013eSMiklos Szeredi if (IS_ERR(forget_req)) { 2762d51013eSMiklos Szeredi fuse_put_request(fc, req); 2772d51013eSMiklos Szeredi return ERR_PTR(PTR_ERR(forget_req)); 2782d51013eSMiklos Szeredi } 2792d51013eSMiklos Szeredi 2807dca9fd3SMiklos Szeredi attr_version = fuse_get_attr_version(fc); 2811fb69e78SMiklos Szeredi 282e5e5558eSMiklos Szeredi fuse_lookup_init(req, dir, entry, &outarg); 283e5e5558eSMiklos Szeredi request_send(fc, req); 284e5e5558eSMiklos Szeredi err = req->out.h.error; 2852d51013eSMiklos Szeredi fuse_put_request(fc, req); 28650322fe7SMiklos Szeredi /* Zero nodeid is same as -ENOENT, but with valid timeout */ 28750322fe7SMiklos Szeredi if (!err && outarg.nodeid && 288a5bfffacSTimo Savola (invalid_nodeid(outarg.nodeid) || 289a5bfffacSTimo Savola !fuse_valid_type(outarg.attr.mode))) 290ee4e5271SMiklos Szeredi err = -EIO; 2918cbdf1e6SMiklos Szeredi if (!err && outarg.nodeid) { 292e5e5558eSMiklos Szeredi inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 2931fb69e78SMiklos Szeredi &outarg.attr, entry_attr_timeout(&outarg), 2941fb69e78SMiklos Szeredi attr_version); 295e5e5558eSMiklos Szeredi if (!inode) { 2962d51013eSMiklos Szeredi fuse_send_forget(fc, forget_req, outarg.nodeid, 1); 2970aa7c699SMiklos Szeredi return ERR_PTR(-ENOMEM); 298e5e5558eSMiklos Szeredi } 299e5e5558eSMiklos Szeredi } 3002d51013eSMiklos Szeredi fuse_put_request(fc, forget_req); 301e5e5558eSMiklos Szeredi if (err && err != -ENOENT) 3020aa7c699SMiklos Szeredi return ERR_PTR(err); 303e5e5558eSMiklos Szeredi 304d2a85164SMiklos Szeredi if (inode && S_ISDIR(inode->i_mode)) { 305d2a85164SMiklos Szeredi mutex_lock(&fc->inst_mutex); 306d2a85164SMiklos Szeredi err = fuse_d_add_directory(entry, inode); 307d2a85164SMiklos Szeredi mutex_unlock(&fc->inst_mutex); 308d2a85164SMiklos Szeredi if (err) { 3090aa7c699SMiklos Szeredi iput(inode); 310d2a85164SMiklos Szeredi return ERR_PTR(err); 311e5e5558eSMiklos Szeredi } 312d2a85164SMiklos Szeredi } else 3130aa7c699SMiklos Szeredi d_add(entry, inode); 314d2a85164SMiklos Szeredi 315e5e5558eSMiklos Szeredi entry->d_op = &fuse_dentry_operations; 3168cbdf1e6SMiklos Szeredi if (!err) 3171fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outarg); 3188cbdf1e6SMiklos Szeredi else 3198cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 3200aa7c699SMiklos Szeredi return NULL; 321e5e5558eSMiklos Szeredi } 322e5e5558eSMiklos Szeredi 3236f9f1180SMiklos Szeredi /* 32451eb01e7SMiklos Szeredi * Synchronous release for the case when something goes wrong in CREATE_OPEN 32551eb01e7SMiklos Szeredi */ 32651eb01e7SMiklos Szeredi static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff, 32751eb01e7SMiklos Szeredi u64 nodeid, int flags) 32851eb01e7SMiklos Szeredi { 329c756e0a4SMiklos Szeredi fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE); 330c756e0a4SMiklos Szeredi ff->reserved_req->force = 1; 331c756e0a4SMiklos Szeredi request_send(fc, ff->reserved_req); 332c756e0a4SMiklos Szeredi fuse_put_request(fc, ff->reserved_req); 333c756e0a4SMiklos Szeredi kfree(ff); 33451eb01e7SMiklos Szeredi } 33551eb01e7SMiklos Szeredi 33651eb01e7SMiklos Szeredi /* 3376f9f1180SMiklos Szeredi * Atomic create+open operation 3386f9f1180SMiklos Szeredi * 3396f9f1180SMiklos Szeredi * If the filesystem doesn't support this, then fall back to separate 3406f9f1180SMiklos Szeredi * 'mknod' + 'open' requests. 3416f9f1180SMiklos Szeredi */ 342fd72faacSMiklos Szeredi static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, 343fd72faacSMiklos Szeredi struct nameidata *nd) 344fd72faacSMiklos Szeredi { 345fd72faacSMiklos Szeredi int err; 346fd72faacSMiklos Szeredi struct inode *inode; 347fd72faacSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 348fd72faacSMiklos Szeredi struct fuse_req *req; 34951eb01e7SMiklos Szeredi struct fuse_req *forget_req; 350fd72faacSMiklos Szeredi struct fuse_open_in inarg; 351fd72faacSMiklos Szeredi struct fuse_open_out outopen; 352fd72faacSMiklos Szeredi struct fuse_entry_out outentry; 353fd72faacSMiklos Szeredi struct fuse_file *ff; 354fd72faacSMiklos Szeredi struct file *file; 355fd72faacSMiklos Szeredi int flags = nd->intent.open.flags - 1; 356fd72faacSMiklos Szeredi 357fd72faacSMiklos Szeredi if (fc->no_create) 358ce1d5a49SMiklos Szeredi return -ENOSYS; 359fd72faacSMiklos Szeredi 36051eb01e7SMiklos Szeredi forget_req = fuse_get_req(fc); 36151eb01e7SMiklos Szeredi if (IS_ERR(forget_req)) 36251eb01e7SMiklos Szeredi return PTR_ERR(forget_req); 36351eb01e7SMiklos Szeredi 364ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 36551eb01e7SMiklos Szeredi err = PTR_ERR(req); 366ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 36751eb01e7SMiklos Szeredi goto out_put_forget_req; 368fd72faacSMiklos Szeredi 369ce1d5a49SMiklos Szeredi err = -ENOMEM; 370fd72faacSMiklos Szeredi ff = fuse_file_alloc(); 371fd72faacSMiklos Szeredi if (!ff) 372fd72faacSMiklos Szeredi goto out_put_request; 373fd72faacSMiklos Szeredi 374fd72faacSMiklos Szeredi flags &= ~O_NOCTTY; 375fd72faacSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 3760e9663eeSMiklos Szeredi memset(&outentry, 0, sizeof(outentry)); 377fd72faacSMiklos Szeredi inarg.flags = flags; 378fd72faacSMiklos Szeredi inarg.mode = mode; 379fd72faacSMiklos Szeredi req->in.h.opcode = FUSE_CREATE; 380fd72faacSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 381fd72faacSMiklos Szeredi req->in.numargs = 2; 382fd72faacSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 383fd72faacSMiklos Szeredi req->in.args[0].value = &inarg; 384fd72faacSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 385fd72faacSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 386fd72faacSMiklos Szeredi req->out.numargs = 2; 3870e9663eeSMiklos Szeredi if (fc->minor < 9) 3880e9663eeSMiklos Szeredi req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; 3890e9663eeSMiklos Szeredi else 390fd72faacSMiklos Szeredi req->out.args[0].size = sizeof(outentry); 391fd72faacSMiklos Szeredi req->out.args[0].value = &outentry; 392fd72faacSMiklos Szeredi req->out.args[1].size = sizeof(outopen); 393fd72faacSMiklos Szeredi req->out.args[1].value = &outopen; 394fd72faacSMiklos Szeredi request_send(fc, req); 395fd72faacSMiklos Szeredi err = req->out.h.error; 396fd72faacSMiklos Szeredi if (err) { 397fd72faacSMiklos Szeredi if (err == -ENOSYS) 398fd72faacSMiklos Szeredi fc->no_create = 1; 399fd72faacSMiklos Szeredi goto out_free_ff; 400fd72faacSMiklos Szeredi } 401fd72faacSMiklos Szeredi 402fd72faacSMiklos Szeredi err = -EIO; 4032827d0b2SMiklos Szeredi if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid)) 404fd72faacSMiklos Szeredi goto out_free_ff; 405fd72faacSMiklos Szeredi 40651eb01e7SMiklos Szeredi fuse_put_request(fc, req); 407fd72faacSMiklos Szeredi inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, 4081fb69e78SMiklos Szeredi &outentry.attr, entry_attr_timeout(&outentry), 0); 409fd72faacSMiklos Szeredi if (!inode) { 410fd72faacSMiklos Szeredi flags &= ~(O_CREAT | O_EXCL | O_TRUNC); 411fd72faacSMiklos Szeredi ff->fh = outopen.fh; 41251eb01e7SMiklos Szeredi fuse_sync_release(fc, ff, outentry.nodeid, flags); 41351eb01e7SMiklos Szeredi fuse_send_forget(fc, forget_req, outentry.nodeid, 1); 41451eb01e7SMiklos Szeredi return -ENOMEM; 415fd72faacSMiklos Szeredi } 41651eb01e7SMiklos Szeredi fuse_put_request(fc, forget_req); 417fd72faacSMiklos Szeredi d_instantiate(entry, inode); 4181fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outentry); 419fd72faacSMiklos Szeredi file = lookup_instantiate_filp(nd, entry, generic_file_open); 420fd72faacSMiklos Szeredi if (IS_ERR(file)) { 421fd72faacSMiklos Szeredi ff->fh = outopen.fh; 42251eb01e7SMiklos Szeredi fuse_sync_release(fc, ff, outentry.nodeid, flags); 423fd72faacSMiklos Szeredi return PTR_ERR(file); 424fd72faacSMiklos Szeredi } 425fd72faacSMiklos Szeredi fuse_finish_open(inode, file, ff, &outopen); 426fd72faacSMiklos Szeredi return 0; 427fd72faacSMiklos Szeredi 428fd72faacSMiklos Szeredi out_free_ff: 429fd72faacSMiklos Szeredi fuse_file_free(ff); 430fd72faacSMiklos Szeredi out_put_request: 431fd72faacSMiklos Szeredi fuse_put_request(fc, req); 43251eb01e7SMiklos Szeredi out_put_forget_req: 43351eb01e7SMiklos Szeredi fuse_put_request(fc, forget_req); 434fd72faacSMiklos Szeredi return err; 435fd72faacSMiklos Szeredi } 436fd72faacSMiklos Szeredi 4376f9f1180SMiklos Szeredi /* 4386f9f1180SMiklos Szeredi * Code shared between mknod, mkdir, symlink and link 4396f9f1180SMiklos Szeredi */ 4409e6268dbSMiklos Szeredi static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, 4419e6268dbSMiklos Szeredi struct inode *dir, struct dentry *entry, 4429e6268dbSMiklos Szeredi int mode) 4439e6268dbSMiklos Szeredi { 4449e6268dbSMiklos Szeredi struct fuse_entry_out outarg; 4459e6268dbSMiklos Szeredi struct inode *inode; 4469e6268dbSMiklos Szeredi int err; 4472d51013eSMiklos Szeredi struct fuse_req *forget_req; 4482d51013eSMiklos Szeredi 4492d51013eSMiklos Szeredi forget_req = fuse_get_req(fc); 4502d51013eSMiklos Szeredi if (IS_ERR(forget_req)) { 4512d51013eSMiklos Szeredi fuse_put_request(fc, req); 4522d51013eSMiklos Szeredi return PTR_ERR(forget_req); 4532d51013eSMiklos Szeredi } 4549e6268dbSMiklos Szeredi 4550e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 4569e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 4579e6268dbSMiklos Szeredi req->out.numargs = 1; 4580e9663eeSMiklos Szeredi if (fc->minor < 9) 4590e9663eeSMiklos Szeredi req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; 4600e9663eeSMiklos Szeredi else 4619e6268dbSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 4629e6268dbSMiklos Szeredi req->out.args[0].value = &outarg; 4639e6268dbSMiklos Szeredi request_send(fc, req); 4649e6268dbSMiklos Szeredi err = req->out.h.error; 4659e6268dbSMiklos Szeredi fuse_put_request(fc, req); 4662d51013eSMiklos Szeredi if (err) 4672d51013eSMiklos Szeredi goto out_put_forget_req; 4682d51013eSMiklos Szeredi 46939ee059aSMiklos Szeredi err = -EIO; 47039ee059aSMiklos Szeredi if (invalid_nodeid(outarg.nodeid)) 4712d51013eSMiklos Szeredi goto out_put_forget_req; 47239ee059aSMiklos Szeredi 47339ee059aSMiklos Szeredi if ((outarg.attr.mode ^ mode) & S_IFMT) 4742d51013eSMiklos Szeredi goto out_put_forget_req; 47539ee059aSMiklos Szeredi 4769e6268dbSMiklos Szeredi inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 4771fb69e78SMiklos Szeredi &outarg.attr, entry_attr_timeout(&outarg), 0); 4789e6268dbSMiklos Szeredi if (!inode) { 4792d51013eSMiklos Szeredi fuse_send_forget(fc, forget_req, outarg.nodeid, 1); 4809e6268dbSMiklos Szeredi return -ENOMEM; 4819e6268dbSMiklos Szeredi } 4822d51013eSMiklos Szeredi fuse_put_request(fc, forget_req); 4839e6268dbSMiklos Szeredi 484d2a85164SMiklos Szeredi if (S_ISDIR(inode->i_mode)) { 485d2a85164SMiklos Szeredi struct dentry *alias; 486d2a85164SMiklos Szeredi mutex_lock(&fc->inst_mutex); 487d2a85164SMiklos Szeredi alias = d_find_alias(inode); 488d2a85164SMiklos Szeredi if (alias) { 489d2a85164SMiklos Szeredi /* New directory must have moved since mkdir */ 490d2a85164SMiklos Szeredi mutex_unlock(&fc->inst_mutex); 491d2a85164SMiklos Szeredi dput(alias); 4929e6268dbSMiklos Szeredi iput(inode); 493d2a85164SMiklos Szeredi return -EBUSY; 4949e6268dbSMiklos Szeredi } 4959e6268dbSMiklos Szeredi d_instantiate(entry, inode); 496d2a85164SMiklos Szeredi mutex_unlock(&fc->inst_mutex); 497d2a85164SMiklos Szeredi } else 498d2a85164SMiklos Szeredi d_instantiate(entry, inode); 499d2a85164SMiklos Szeredi 5001fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outarg); 5019e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 5029e6268dbSMiklos Szeredi return 0; 50339ee059aSMiklos Szeredi 5042d51013eSMiklos Szeredi out_put_forget_req: 5052d51013eSMiklos Szeredi fuse_put_request(fc, forget_req); 50639ee059aSMiklos Szeredi return err; 5079e6268dbSMiklos Szeredi } 5089e6268dbSMiklos Szeredi 5099e6268dbSMiklos Szeredi static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, 5109e6268dbSMiklos Szeredi dev_t rdev) 5119e6268dbSMiklos Szeredi { 5129e6268dbSMiklos Szeredi struct fuse_mknod_in inarg; 5139e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 514ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 515ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 516ce1d5a49SMiklos Szeredi return PTR_ERR(req); 5179e6268dbSMiklos Szeredi 5189e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 5199e6268dbSMiklos Szeredi inarg.mode = mode; 5209e6268dbSMiklos Szeredi inarg.rdev = new_encode_dev(rdev); 5219e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_MKNOD; 5229e6268dbSMiklos Szeredi req->in.numargs = 2; 5239e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 5249e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 5259e6268dbSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 5269e6268dbSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 5279e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, mode); 5289e6268dbSMiklos Szeredi } 5299e6268dbSMiklos Szeredi 5309e6268dbSMiklos Szeredi static int fuse_create(struct inode *dir, struct dentry *entry, int mode, 5319e6268dbSMiklos Szeredi struct nameidata *nd) 5329e6268dbSMiklos Szeredi { 533b9ba347fSMiklos Szeredi if (nd && (nd->flags & LOOKUP_OPEN)) { 534fd72faacSMiklos Szeredi int err = fuse_create_open(dir, entry, mode, nd); 535fd72faacSMiklos Szeredi if (err != -ENOSYS) 536fd72faacSMiklos Szeredi return err; 537fd72faacSMiklos Szeredi /* Fall back on mknod */ 538fd72faacSMiklos Szeredi } 5399e6268dbSMiklos Szeredi return fuse_mknod(dir, entry, mode, 0); 5409e6268dbSMiklos Szeredi } 5419e6268dbSMiklos Szeredi 5429e6268dbSMiklos Szeredi static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode) 5439e6268dbSMiklos Szeredi { 5449e6268dbSMiklos Szeredi struct fuse_mkdir_in inarg; 5459e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 546ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 547ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 548ce1d5a49SMiklos Szeredi return PTR_ERR(req); 5499e6268dbSMiklos Szeredi 5509e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 5519e6268dbSMiklos Szeredi inarg.mode = mode; 5529e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_MKDIR; 5539e6268dbSMiklos Szeredi req->in.numargs = 2; 5549e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 5559e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 5569e6268dbSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 5579e6268dbSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 5589e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, S_IFDIR); 5599e6268dbSMiklos Szeredi } 5609e6268dbSMiklos Szeredi 5619e6268dbSMiklos Szeredi static int fuse_symlink(struct inode *dir, struct dentry *entry, 5629e6268dbSMiklos Szeredi const char *link) 5639e6268dbSMiklos Szeredi { 5649e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 5659e6268dbSMiklos Szeredi unsigned len = strlen(link) + 1; 566ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 567ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 568ce1d5a49SMiklos Szeredi return PTR_ERR(req); 5699e6268dbSMiklos Szeredi 5709e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_SYMLINK; 5719e6268dbSMiklos Szeredi req->in.numargs = 2; 5729e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 5739e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 5749e6268dbSMiklos Szeredi req->in.args[1].size = len; 5759e6268dbSMiklos Szeredi req->in.args[1].value = link; 5769e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, S_IFLNK); 5779e6268dbSMiklos Szeredi } 5789e6268dbSMiklos Szeredi 5799e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry) 5809e6268dbSMiklos Szeredi { 5819e6268dbSMiklos Szeredi int err; 5829e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 583ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 584ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 585ce1d5a49SMiklos Szeredi return PTR_ERR(req); 5869e6268dbSMiklos Szeredi 5879e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_UNLINK; 5889e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 5899e6268dbSMiklos Szeredi req->in.numargs = 1; 5909e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 5919e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 5929e6268dbSMiklos Szeredi request_send(fc, req); 5939e6268dbSMiklos Szeredi err = req->out.h.error; 5949e6268dbSMiklos Szeredi fuse_put_request(fc, req); 5959e6268dbSMiklos Szeredi if (!err) { 5969e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 5979e6268dbSMiklos Szeredi 5989e6268dbSMiklos Szeredi /* Set nlink to zero so the inode can be cleared, if 5999e6268dbSMiklos Szeredi the inode does have more links this will be 6009e6268dbSMiklos Szeredi discovered at the next lookup/getattr */ 601ce71ec36SDave Hansen clear_nlink(inode); 6029e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 6039e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 6048cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 6059e6268dbSMiklos Szeredi } else if (err == -EINTR) 6069e6268dbSMiklos Szeredi fuse_invalidate_entry(entry); 6079e6268dbSMiklos Szeredi return err; 6089e6268dbSMiklos Szeredi } 6099e6268dbSMiklos Szeredi 6109e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry) 6119e6268dbSMiklos Szeredi { 6129e6268dbSMiklos Szeredi int err; 6139e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 614ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 615ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 616ce1d5a49SMiklos Szeredi return PTR_ERR(req); 6179e6268dbSMiklos Szeredi 6189e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_RMDIR; 6199e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 6209e6268dbSMiklos Szeredi req->in.numargs = 1; 6219e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 6229e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 6239e6268dbSMiklos Szeredi request_send(fc, req); 6249e6268dbSMiklos Szeredi err = req->out.h.error; 6259e6268dbSMiklos Szeredi fuse_put_request(fc, req); 6269e6268dbSMiklos Szeredi if (!err) { 627ce71ec36SDave Hansen clear_nlink(entry->d_inode); 6289e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 6298cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 6309e6268dbSMiklos Szeredi } else if (err == -EINTR) 6319e6268dbSMiklos Szeredi fuse_invalidate_entry(entry); 6329e6268dbSMiklos Szeredi return err; 6339e6268dbSMiklos Szeredi } 6349e6268dbSMiklos Szeredi 6359e6268dbSMiklos Szeredi static int fuse_rename(struct inode *olddir, struct dentry *oldent, 6369e6268dbSMiklos Szeredi struct inode *newdir, struct dentry *newent) 6379e6268dbSMiklos Szeredi { 6389e6268dbSMiklos Szeredi int err; 6399e6268dbSMiklos Szeredi struct fuse_rename_in inarg; 6409e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(olddir); 641ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 642ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 643ce1d5a49SMiklos Szeredi return PTR_ERR(req); 6449e6268dbSMiklos Szeredi 6459e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 6469e6268dbSMiklos Szeredi inarg.newdir = get_node_id(newdir); 6479e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_RENAME; 6489e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(olddir); 6499e6268dbSMiklos Szeredi req->in.numargs = 3; 6509e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 6519e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 6529e6268dbSMiklos Szeredi req->in.args[1].size = oldent->d_name.len + 1; 6539e6268dbSMiklos Szeredi req->in.args[1].value = oldent->d_name.name; 6549e6268dbSMiklos Szeredi req->in.args[2].size = newent->d_name.len + 1; 6559e6268dbSMiklos Szeredi req->in.args[2].value = newent->d_name.name; 6569e6268dbSMiklos Szeredi request_send(fc, req); 6579e6268dbSMiklos Szeredi err = req->out.h.error; 6589e6268dbSMiklos Szeredi fuse_put_request(fc, req); 6599e6268dbSMiklos Szeredi if (!err) { 6609e6268dbSMiklos Szeredi fuse_invalidate_attr(olddir); 6619e6268dbSMiklos Szeredi if (olddir != newdir) 6629e6268dbSMiklos Szeredi fuse_invalidate_attr(newdir); 6638cbdf1e6SMiklos Szeredi 6648cbdf1e6SMiklos Szeredi /* newent will end up negative */ 6658cbdf1e6SMiklos Szeredi if (newent->d_inode) 6668cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(newent); 6679e6268dbSMiklos Szeredi } else if (err == -EINTR) { 6689e6268dbSMiklos Szeredi /* If request was interrupted, DEITY only knows if the 6699e6268dbSMiklos Szeredi rename actually took place. If the invalidation 6709e6268dbSMiklos Szeredi fails (e.g. some process has CWD under the renamed 6719e6268dbSMiklos Szeredi directory), then there can be inconsistency between 6729e6268dbSMiklos Szeredi the dcache and the real filesystem. Tough luck. */ 6739e6268dbSMiklos Szeredi fuse_invalidate_entry(oldent); 6749e6268dbSMiklos Szeredi if (newent->d_inode) 6759e6268dbSMiklos Szeredi fuse_invalidate_entry(newent); 6769e6268dbSMiklos Szeredi } 6779e6268dbSMiklos Szeredi 6789e6268dbSMiklos Szeredi return err; 6799e6268dbSMiklos Szeredi } 6809e6268dbSMiklos Szeredi 6819e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir, 6829e6268dbSMiklos Szeredi struct dentry *newent) 6839e6268dbSMiklos Szeredi { 6849e6268dbSMiklos Szeredi int err; 6859e6268dbSMiklos Szeredi struct fuse_link_in inarg; 6869e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 6879e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 688ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 689ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 690ce1d5a49SMiklos Szeredi return PTR_ERR(req); 6919e6268dbSMiklos Szeredi 6929e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 6939e6268dbSMiklos Szeredi inarg.oldnodeid = get_node_id(inode); 6949e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_LINK; 6959e6268dbSMiklos Szeredi req->in.numargs = 2; 6969e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 6979e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 6989e6268dbSMiklos Szeredi req->in.args[1].size = newent->d_name.len + 1; 6999e6268dbSMiklos Szeredi req->in.args[1].value = newent->d_name.name; 7009e6268dbSMiklos Szeredi err = create_new_entry(fc, req, newdir, newent, inode->i_mode); 7019e6268dbSMiklos Szeredi /* Contrary to "normal" filesystems it can happen that link 7029e6268dbSMiklos Szeredi makes two "logical" inodes point to the same "physical" 7039e6268dbSMiklos Szeredi inode. We invalidate the attributes of the old one, so it 7049e6268dbSMiklos Szeredi will reflect changes in the backing inode (link count, 7059e6268dbSMiklos Szeredi etc.) 7069e6268dbSMiklos Szeredi */ 7079e6268dbSMiklos Szeredi if (!err || err == -EINTR) 7089e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 7099e6268dbSMiklos Szeredi return err; 7109e6268dbSMiklos Szeredi } 7119e6268dbSMiklos Szeredi 7121fb69e78SMiklos Szeredi static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, 7131fb69e78SMiklos Szeredi struct kstat *stat) 7141fb69e78SMiklos Szeredi { 7151fb69e78SMiklos Szeredi stat->dev = inode->i_sb->s_dev; 7161fb69e78SMiklos Szeredi stat->ino = attr->ino; 7171fb69e78SMiklos Szeredi stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); 7181fb69e78SMiklos Szeredi stat->nlink = attr->nlink; 7191fb69e78SMiklos Szeredi stat->uid = attr->uid; 7201fb69e78SMiklos Szeredi stat->gid = attr->gid; 7211fb69e78SMiklos Szeredi stat->rdev = inode->i_rdev; 7221fb69e78SMiklos Szeredi stat->atime.tv_sec = attr->atime; 7231fb69e78SMiklos Szeredi stat->atime.tv_nsec = attr->atimensec; 7241fb69e78SMiklos Szeredi stat->mtime.tv_sec = attr->mtime; 7251fb69e78SMiklos Szeredi stat->mtime.tv_nsec = attr->mtimensec; 7261fb69e78SMiklos Szeredi stat->ctime.tv_sec = attr->ctime; 7271fb69e78SMiklos Szeredi stat->ctime.tv_nsec = attr->ctimensec; 7281fb69e78SMiklos Szeredi stat->size = attr->size; 7291fb69e78SMiklos Szeredi stat->blocks = attr->blocks; 7301fb69e78SMiklos Szeredi stat->blksize = (1 << inode->i_blkbits); 7311fb69e78SMiklos Szeredi } 7321fb69e78SMiklos Szeredi 733c79e322fSMiklos Szeredi static int fuse_do_getattr(struct inode *inode, struct kstat *stat, 734c79e322fSMiklos Szeredi struct file *file) 735e5e5558eSMiklos Szeredi { 736e5e5558eSMiklos Szeredi int err; 737c79e322fSMiklos Szeredi struct fuse_getattr_in inarg; 738c79e322fSMiklos Szeredi struct fuse_attr_out outarg; 739e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 7401fb69e78SMiklos Szeredi struct fuse_req *req; 7411fb69e78SMiklos Szeredi u64 attr_version; 7421fb69e78SMiklos Szeredi 7431fb69e78SMiklos Szeredi req = fuse_get_req(fc); 744ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 745ce1d5a49SMiklos Szeredi return PTR_ERR(req); 746e5e5558eSMiklos Szeredi 7477dca9fd3SMiklos Szeredi attr_version = fuse_get_attr_version(fc); 7481fb69e78SMiklos Szeredi 749c79e322fSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 7500e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 751c79e322fSMiklos Szeredi /* Directories have separate file-handle space */ 752c79e322fSMiklos Szeredi if (file && S_ISREG(inode->i_mode)) { 753c79e322fSMiklos Szeredi struct fuse_file *ff = file->private_data; 754c79e322fSMiklos Szeredi 755c79e322fSMiklos Szeredi inarg.getattr_flags |= FUSE_GETATTR_FH; 756c79e322fSMiklos Szeredi inarg.fh = ff->fh; 757c79e322fSMiklos Szeredi } 758e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_GETATTR; 759e5e5558eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 760c79e322fSMiklos Szeredi req->in.numargs = 1; 761c79e322fSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 762c79e322fSMiklos Szeredi req->in.args[0].value = &inarg; 763e5e5558eSMiklos Szeredi req->out.numargs = 1; 7640e9663eeSMiklos Szeredi if (fc->minor < 9) 7650e9663eeSMiklos Szeredi req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; 7660e9663eeSMiklos Szeredi else 767c79e322fSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 768c79e322fSMiklos Szeredi req->out.args[0].value = &outarg; 769e5e5558eSMiklos Szeredi request_send(fc, req); 770e5e5558eSMiklos Szeredi err = req->out.h.error; 771e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 772e5e5558eSMiklos Szeredi if (!err) { 773c79e322fSMiklos Szeredi if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { 774e5e5558eSMiklos Szeredi make_bad_inode(inode); 775e5e5558eSMiklos Szeredi err = -EIO; 776e5e5558eSMiklos Szeredi } else { 777c79e322fSMiklos Szeredi fuse_change_attributes(inode, &outarg.attr, 778c79e322fSMiklos Szeredi attr_timeout(&outarg), 7791fb69e78SMiklos Szeredi attr_version); 7801fb69e78SMiklos Szeredi if (stat) 781c79e322fSMiklos Szeredi fuse_fillattr(inode, &outarg.attr, stat); 782e5e5558eSMiklos Szeredi } 783e5e5558eSMiklos Szeredi } 784e5e5558eSMiklos Szeredi return err; 785e5e5558eSMiklos Szeredi } 786e5e5558eSMiklos Szeredi 787bcb4be80SMiklos Szeredi int fuse_update_attributes(struct inode *inode, struct kstat *stat, 788bcb4be80SMiklos Szeredi struct file *file, bool *refreshed) 789bcb4be80SMiklos Szeredi { 790bcb4be80SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 791bcb4be80SMiklos Szeredi int err; 792bcb4be80SMiklos Szeredi bool r; 793bcb4be80SMiklos Szeredi 794bcb4be80SMiklos Szeredi if (fi->i_time < get_jiffies_64()) { 795bcb4be80SMiklos Szeredi r = true; 796bcb4be80SMiklos Szeredi err = fuse_do_getattr(inode, stat, file); 797bcb4be80SMiklos Szeredi } else { 798bcb4be80SMiklos Szeredi r = false; 799bcb4be80SMiklos Szeredi err = 0; 800bcb4be80SMiklos Szeredi if (stat) { 801bcb4be80SMiklos Szeredi generic_fillattr(inode, stat); 802bcb4be80SMiklos Szeredi stat->mode = fi->orig_i_mode; 803bcb4be80SMiklos Szeredi } 804bcb4be80SMiklos Szeredi } 805bcb4be80SMiklos Szeredi 806bcb4be80SMiklos Szeredi if (refreshed != NULL) 807bcb4be80SMiklos Szeredi *refreshed = r; 808bcb4be80SMiklos Szeredi 809bcb4be80SMiklos Szeredi return err; 810bcb4be80SMiklos Szeredi } 811bcb4be80SMiklos Szeredi 81287729a55SMiklos Szeredi /* 81387729a55SMiklos Szeredi * Calling into a user-controlled filesystem gives the filesystem 81487729a55SMiklos Szeredi * daemon ptrace-like capabilities over the requester process. This 81587729a55SMiklos Szeredi * means, that the filesystem daemon is able to record the exact 81687729a55SMiklos Szeredi * filesystem operations performed, and can also control the behavior 81787729a55SMiklos Szeredi * of the requester process in otherwise impossible ways. For example 81887729a55SMiklos Szeredi * it can delay the operation for arbitrary length of time allowing 81987729a55SMiklos Szeredi * DoS against the requester. 82087729a55SMiklos Szeredi * 82187729a55SMiklos Szeredi * For this reason only those processes can call into the filesystem, 82287729a55SMiklos Szeredi * for which the owner of the mount has ptrace privilege. This 82387729a55SMiklos Szeredi * excludes processes started by other users, suid or sgid processes. 82487729a55SMiklos Szeredi */ 825e57ac683SMiklos Szeredi int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task) 82687729a55SMiklos Szeredi { 82787729a55SMiklos Szeredi if (fc->flags & FUSE_ALLOW_OTHER) 82887729a55SMiklos Szeredi return 1; 82987729a55SMiklos Szeredi 83087729a55SMiklos Szeredi if (task->euid == fc->user_id && 83187729a55SMiklos Szeredi task->suid == fc->user_id && 83287729a55SMiklos Szeredi task->uid == fc->user_id && 83387729a55SMiklos Szeredi task->egid == fc->group_id && 83487729a55SMiklos Szeredi task->sgid == fc->group_id && 83587729a55SMiklos Szeredi task->gid == fc->group_id) 83687729a55SMiklos Szeredi return 1; 83787729a55SMiklos Szeredi 83887729a55SMiklos Szeredi return 0; 83987729a55SMiklos Szeredi } 84087729a55SMiklos Szeredi 84131d40d74SMiklos Szeredi static int fuse_access(struct inode *inode, int mask) 84231d40d74SMiklos Szeredi { 84331d40d74SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 84431d40d74SMiklos Szeredi struct fuse_req *req; 84531d40d74SMiklos Szeredi struct fuse_access_in inarg; 84631d40d74SMiklos Szeredi int err; 84731d40d74SMiklos Szeredi 84831d40d74SMiklos Szeredi if (fc->no_access) 84931d40d74SMiklos Szeredi return 0; 85031d40d74SMiklos Szeredi 851ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 852ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 853ce1d5a49SMiklos Szeredi return PTR_ERR(req); 85431d40d74SMiklos Szeredi 85531d40d74SMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 85631d40d74SMiklos Szeredi inarg.mask = mask; 85731d40d74SMiklos Szeredi req->in.h.opcode = FUSE_ACCESS; 85831d40d74SMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 85931d40d74SMiklos Szeredi req->in.numargs = 1; 86031d40d74SMiklos Szeredi req->in.args[0].size = sizeof(inarg); 86131d40d74SMiklos Szeredi req->in.args[0].value = &inarg; 86231d40d74SMiklos Szeredi request_send(fc, req); 86331d40d74SMiklos Szeredi err = req->out.h.error; 86431d40d74SMiklos Szeredi fuse_put_request(fc, req); 86531d40d74SMiklos Szeredi if (err == -ENOSYS) { 86631d40d74SMiklos Szeredi fc->no_access = 1; 86731d40d74SMiklos Szeredi err = 0; 86831d40d74SMiklos Szeredi } 86931d40d74SMiklos Szeredi return err; 87031d40d74SMiklos Szeredi } 87131d40d74SMiklos Szeredi 8726f9f1180SMiklos Szeredi /* 8736f9f1180SMiklos Szeredi * Check permission. The two basic access models of FUSE are: 8746f9f1180SMiklos Szeredi * 8756f9f1180SMiklos Szeredi * 1) Local access checking ('default_permissions' mount option) based 8766f9f1180SMiklos Szeredi * on file mode. This is the plain old disk filesystem permission 8776f9f1180SMiklos Szeredi * modell. 8786f9f1180SMiklos Szeredi * 8796f9f1180SMiklos Szeredi * 2) "Remote" access checking, where server is responsible for 8806f9f1180SMiklos Szeredi * checking permission in each inode operation. An exception to this 8816f9f1180SMiklos Szeredi * is if ->permission() was invoked from sys_access() in which case an 8826f9f1180SMiklos Szeredi * access request is sent. Execute permission is still checked 8836f9f1180SMiklos Szeredi * locally based on file mode. 8846f9f1180SMiklos Szeredi */ 885e5e5558eSMiklos Szeredi static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) 886e5e5558eSMiklos Szeredi { 887e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 888244f6385SMiklos Szeredi bool refreshed = false; 889244f6385SMiklos Szeredi int err = 0; 890e5e5558eSMiklos Szeredi 89187729a55SMiklos Szeredi if (!fuse_allow_task(fc, current)) 892e5e5558eSMiklos Szeredi return -EACCES; 893244f6385SMiklos Szeredi 894244f6385SMiklos Szeredi /* 895e8e96157SMiklos Szeredi * If attributes are needed, refresh them before proceeding 896244f6385SMiklos Szeredi */ 897e8e96157SMiklos Szeredi if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) || 898e8e96157SMiklos Szeredi ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { 899bcb4be80SMiklos Szeredi err = fuse_update_attributes(inode, NULL, NULL, &refreshed); 900244f6385SMiklos Szeredi if (err) 901244f6385SMiklos Szeredi return err; 9021fb69e78SMiklos Szeredi } 903244f6385SMiklos Szeredi 904244f6385SMiklos Szeredi if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 9051e9a4ed9SMiklos Szeredi int err = generic_permission(inode, mask, NULL); 9061e9a4ed9SMiklos Szeredi 9071e9a4ed9SMiklos Szeredi /* If permission is denied, try to refresh file 9081e9a4ed9SMiklos Szeredi attributes. This is also needed, because the root 9091e9a4ed9SMiklos Szeredi node will at first have no permissions */ 910244f6385SMiklos Szeredi if (err == -EACCES && !refreshed) { 911c79e322fSMiklos Szeredi err = fuse_do_getattr(inode, NULL, NULL); 9121e9a4ed9SMiklos Szeredi if (!err) 9131e9a4ed9SMiklos Szeredi err = generic_permission(inode, mask, NULL); 9141e9a4ed9SMiklos Szeredi } 9151e9a4ed9SMiklos Szeredi 9166f9f1180SMiklos Szeredi /* Note: the opposite of the above test does not 9176f9f1180SMiklos Szeredi exist. So if permissions are revoked this won't be 9186f9f1180SMiklos Szeredi noticed immediately, only after the attribute 9196f9f1180SMiklos Szeredi timeout has expired */ 920e8e96157SMiklos Szeredi } else if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR))) { 921e8e96157SMiklos Szeredi err = fuse_access(inode, mask); 922e8e96157SMiklos Szeredi } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { 923e8e96157SMiklos Szeredi if (!(inode->i_mode & S_IXUGO)) { 924e8e96157SMiklos Szeredi if (refreshed) 925e5e5558eSMiklos Szeredi return -EACCES; 92631d40d74SMiklos Szeredi 927c79e322fSMiklos Szeredi err = fuse_do_getattr(inode, NULL, NULL); 928e8e96157SMiklos Szeredi if (!err && !(inode->i_mode & S_IXUGO)) 929e8e96157SMiklos Szeredi return -EACCES; 930e8e96157SMiklos Szeredi } 931e5e5558eSMiklos Szeredi } 932244f6385SMiklos Szeredi return err; 933e5e5558eSMiklos Szeredi } 934e5e5558eSMiklos Szeredi 935e5e5558eSMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file, 936e5e5558eSMiklos Szeredi void *dstbuf, filldir_t filldir) 937e5e5558eSMiklos Szeredi { 938e5e5558eSMiklos Szeredi while (nbytes >= FUSE_NAME_OFFSET) { 939e5e5558eSMiklos Szeredi struct fuse_dirent *dirent = (struct fuse_dirent *) buf; 940e5e5558eSMiklos Szeredi size_t reclen = FUSE_DIRENT_SIZE(dirent); 941e5e5558eSMiklos Szeredi int over; 942e5e5558eSMiklos Szeredi if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) 943e5e5558eSMiklos Szeredi return -EIO; 944e5e5558eSMiklos Szeredi if (reclen > nbytes) 945e5e5558eSMiklos Szeredi break; 946e5e5558eSMiklos Szeredi 947e5e5558eSMiklos Szeredi over = filldir(dstbuf, dirent->name, dirent->namelen, 948e5e5558eSMiklos Szeredi file->f_pos, dirent->ino, dirent->type); 949e5e5558eSMiklos Szeredi if (over) 950e5e5558eSMiklos Szeredi break; 951e5e5558eSMiklos Szeredi 952e5e5558eSMiklos Szeredi buf += reclen; 953e5e5558eSMiklos Szeredi nbytes -= reclen; 954e5e5558eSMiklos Szeredi file->f_pos = dirent->off; 955e5e5558eSMiklos Szeredi } 956e5e5558eSMiklos Szeredi 957e5e5558eSMiklos Szeredi return 0; 958e5e5558eSMiklos Szeredi } 959e5e5558eSMiklos Szeredi 960e5e5558eSMiklos Szeredi static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) 961e5e5558eSMiklos Szeredi { 96204730fefSMiklos Szeredi int err; 96304730fefSMiklos Szeredi size_t nbytes; 96404730fefSMiklos Szeredi struct page *page; 9657706a9d6SJosef Sipek struct inode *inode = file->f_path.dentry->d_inode; 96604730fefSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 967248d86e8SMiklos Szeredi struct fuse_req *req; 968248d86e8SMiklos Szeredi 969248d86e8SMiklos Szeredi if (is_bad_inode(inode)) 970248d86e8SMiklos Szeredi return -EIO; 971248d86e8SMiklos Szeredi 972ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 973ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 974ce1d5a49SMiklos Szeredi return PTR_ERR(req); 975e5e5558eSMiklos Szeredi 97604730fefSMiklos Szeredi page = alloc_page(GFP_KERNEL); 97704730fefSMiklos Szeredi if (!page) { 97804730fefSMiklos Szeredi fuse_put_request(fc, req); 979e5e5558eSMiklos Szeredi return -ENOMEM; 98004730fefSMiklos Szeredi } 98104730fefSMiklos Szeredi req->num_pages = 1; 98204730fefSMiklos Szeredi req->pages[0] = page; 983*a6643094SMiklos Szeredi fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR); 984361b1eb5SMiklos Szeredi request_send(fc, req); 985361b1eb5SMiklos Szeredi nbytes = req->out.args[0].size; 98604730fefSMiklos Szeredi err = req->out.h.error; 98704730fefSMiklos Szeredi fuse_put_request(fc, req); 98804730fefSMiklos Szeredi if (!err) 98904730fefSMiklos Szeredi err = parse_dirfile(page_address(page), nbytes, file, dstbuf, 99004730fefSMiklos Szeredi filldir); 991e5e5558eSMiklos Szeredi 99204730fefSMiklos Szeredi __free_page(page); 993b36c31baSMiklos Szeredi fuse_invalidate_attr(inode); /* atime changed */ 99404730fefSMiklos Szeredi return err; 995e5e5558eSMiklos Szeredi } 996e5e5558eSMiklos Szeredi 997e5e5558eSMiklos Szeredi static char *read_link(struct dentry *dentry) 998e5e5558eSMiklos Szeredi { 999e5e5558eSMiklos Szeredi struct inode *inode = dentry->d_inode; 1000e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1001ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 1002e5e5558eSMiklos Szeredi char *link; 1003e5e5558eSMiklos Szeredi 1004ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1005ce1d5a49SMiklos Szeredi return ERR_PTR(PTR_ERR(req)); 1006e5e5558eSMiklos Szeredi 1007e5e5558eSMiklos Szeredi link = (char *) __get_free_page(GFP_KERNEL); 1008e5e5558eSMiklos Szeredi if (!link) { 1009e5e5558eSMiklos Szeredi link = ERR_PTR(-ENOMEM); 1010e5e5558eSMiklos Szeredi goto out; 1011e5e5558eSMiklos Szeredi } 1012e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_READLINK; 1013e5e5558eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 1014e5e5558eSMiklos Szeredi req->out.argvar = 1; 1015e5e5558eSMiklos Szeredi req->out.numargs = 1; 1016e5e5558eSMiklos Szeredi req->out.args[0].size = PAGE_SIZE - 1; 1017e5e5558eSMiklos Szeredi req->out.args[0].value = link; 1018e5e5558eSMiklos Szeredi request_send(fc, req); 1019e5e5558eSMiklos Szeredi if (req->out.h.error) { 1020e5e5558eSMiklos Szeredi free_page((unsigned long) link); 1021e5e5558eSMiklos Szeredi link = ERR_PTR(req->out.h.error); 1022e5e5558eSMiklos Szeredi } else 1023e5e5558eSMiklos Szeredi link[req->out.args[0].size] = '\0'; 1024e5e5558eSMiklos Szeredi out: 1025e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 1026b36c31baSMiklos Szeredi fuse_invalidate_attr(inode); /* atime changed */ 1027e5e5558eSMiklos Szeredi return link; 1028e5e5558eSMiklos Szeredi } 1029e5e5558eSMiklos Szeredi 1030e5e5558eSMiklos Szeredi static void free_link(char *link) 1031e5e5558eSMiklos Szeredi { 1032e5e5558eSMiklos Szeredi if (!IS_ERR(link)) 1033e5e5558eSMiklos Szeredi free_page((unsigned long) link); 1034e5e5558eSMiklos Szeredi } 1035e5e5558eSMiklos Szeredi 1036e5e5558eSMiklos Szeredi static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd) 1037e5e5558eSMiklos Szeredi { 1038e5e5558eSMiklos Szeredi nd_set_link(nd, read_link(dentry)); 1039e5e5558eSMiklos Szeredi return NULL; 1040e5e5558eSMiklos Szeredi } 1041e5e5558eSMiklos Szeredi 1042e5e5558eSMiklos Szeredi static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c) 1043e5e5558eSMiklos Szeredi { 1044e5e5558eSMiklos Szeredi free_link(nd_get_link(nd)); 1045e5e5558eSMiklos Szeredi } 1046e5e5558eSMiklos Szeredi 1047e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file) 1048e5e5558eSMiklos Szeredi { 104904730fefSMiklos Szeredi return fuse_open_common(inode, file, 1); 1050e5e5558eSMiklos Szeredi } 1051e5e5558eSMiklos Szeredi 1052e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file) 1053e5e5558eSMiklos Szeredi { 105404730fefSMiklos Szeredi return fuse_release_common(inode, file, 1); 1055e5e5558eSMiklos Szeredi } 1056e5e5558eSMiklos Szeredi 105782547981SMiklos Szeredi static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync) 105882547981SMiklos Szeredi { 105982547981SMiklos Szeredi /* nfsd can call this with no file */ 106082547981SMiklos Szeredi return file ? fuse_fsync_common(file, de, datasync, 1) : 0; 106182547981SMiklos Szeredi } 106282547981SMiklos Szeredi 106317637cbaSMiklos Szeredi static bool update_mtime(unsigned ivalid) 106417637cbaSMiklos Szeredi { 106517637cbaSMiklos Szeredi /* Always update if mtime is explicitly set */ 106617637cbaSMiklos Szeredi if (ivalid & ATTR_MTIME_SET) 106717637cbaSMiklos Szeredi return true; 106817637cbaSMiklos Szeredi 106917637cbaSMiklos Szeredi /* If it's an open(O_TRUNC) or an ftruncate(), don't update */ 107017637cbaSMiklos Szeredi if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE))) 107117637cbaSMiklos Szeredi return false; 107217637cbaSMiklos Szeredi 107317637cbaSMiklos Szeredi /* In all other cases update */ 107417637cbaSMiklos Szeredi return true; 107517637cbaSMiklos Szeredi } 107617637cbaSMiklos Szeredi 1077befc649cSMiklos Szeredi static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) 10789e6268dbSMiklos Szeredi { 10799e6268dbSMiklos Szeredi unsigned ivalid = iattr->ia_valid; 10809e6268dbSMiklos Szeredi 10819e6268dbSMiklos Szeredi if (ivalid & ATTR_MODE) 1082befc649cSMiklos Szeredi arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode; 10839e6268dbSMiklos Szeredi if (ivalid & ATTR_UID) 1084befc649cSMiklos Szeredi arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid; 10859e6268dbSMiklos Szeredi if (ivalid & ATTR_GID) 1086befc649cSMiklos Szeredi arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid; 10879e6268dbSMiklos Szeredi if (ivalid & ATTR_SIZE) 1088befc649cSMiklos Szeredi arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size; 108917637cbaSMiklos Szeredi if (ivalid & ATTR_ATIME) { 109017637cbaSMiklos Szeredi arg->valid |= FATTR_ATIME; 1091befc649cSMiklos Szeredi arg->atime = iattr->ia_atime.tv_sec; 109217637cbaSMiklos Szeredi arg->atimensec = iattr->ia_atime.tv_nsec; 109317637cbaSMiklos Szeredi if (!(ivalid & ATTR_ATIME_SET)) 109417637cbaSMiklos Szeredi arg->valid |= FATTR_ATIME_NOW; 109517637cbaSMiklos Szeredi } 109617637cbaSMiklos Szeredi if ((ivalid & ATTR_MTIME) && update_mtime(ivalid)) { 109717637cbaSMiklos Szeredi arg->valid |= FATTR_MTIME; 1098befc649cSMiklos Szeredi arg->mtime = iattr->ia_mtime.tv_sec; 109917637cbaSMiklos Szeredi arg->mtimensec = iattr->ia_mtime.tv_nsec; 110017637cbaSMiklos Szeredi if (!(ivalid & ATTR_MTIME_SET)) 110117637cbaSMiklos Szeredi arg->valid |= FATTR_MTIME_NOW; 11029e6268dbSMiklos Szeredi } 11039e6268dbSMiklos Szeredi } 11049e6268dbSMiklos Szeredi 11056f9f1180SMiklos Szeredi /* 11066f9f1180SMiklos Szeredi * Set attributes, and at the same time refresh them. 11076f9f1180SMiklos Szeredi * 11086f9f1180SMiklos Szeredi * Truncation is slightly complicated, because the 'truncate' request 11096f9f1180SMiklos Szeredi * may fail, in which case we don't want to touch the mapping. 11109ffbb916SMiklos Szeredi * vmtruncate() doesn't allow for this case, so do the rlimit checking 11119ffbb916SMiklos Szeredi * and the actual truncation by hand. 11126f9f1180SMiklos Szeredi */ 111349d4914fSMiklos Szeredi static int fuse_do_setattr(struct dentry *entry, struct iattr *attr, 111449d4914fSMiklos Szeredi struct file *file) 11159e6268dbSMiklos Szeredi { 11169e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 11179e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 11189e6268dbSMiklos Szeredi struct fuse_req *req; 11199e6268dbSMiklos Szeredi struct fuse_setattr_in inarg; 11209e6268dbSMiklos Szeredi struct fuse_attr_out outarg; 11219e6268dbSMiklos Szeredi int err; 11229e6268dbSMiklos Szeredi 1123e57ac683SMiklos Szeredi if (!fuse_allow_task(fc, current)) 1124e57ac683SMiklos Szeredi return -EACCES; 1125e57ac683SMiklos Szeredi 11261e9a4ed9SMiklos Szeredi if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 11271e9a4ed9SMiklos Szeredi err = inode_change_ok(inode, attr); 11281e9a4ed9SMiklos Szeredi if (err) 11291e9a4ed9SMiklos Szeredi return err; 11301e9a4ed9SMiklos Szeredi } 11311e9a4ed9SMiklos Szeredi 11326ff958edSMiklos Szeredi if ((attr->ia_valid & ATTR_OPEN) && fc->atomic_o_trunc) 11336ff958edSMiklos Szeredi return 0; 11346ff958edSMiklos Szeredi 11359e6268dbSMiklos Szeredi if (attr->ia_valid & ATTR_SIZE) { 11369e6268dbSMiklos Szeredi unsigned long limit; 1137b2d2272fSMiklos Szeredi if (IS_SWAPFILE(inode)) 1138b2d2272fSMiklos Szeredi return -ETXTBSY; 11399e6268dbSMiklos Szeredi limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; 11409e6268dbSMiklos Szeredi if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) { 11419e6268dbSMiklos Szeredi send_sig(SIGXFSZ, current, 0); 11429e6268dbSMiklos Szeredi return -EFBIG; 11439e6268dbSMiklos Szeredi } 11449e6268dbSMiklos Szeredi } 11459e6268dbSMiklos Szeredi 1146ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1147ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1148ce1d5a49SMiklos Szeredi return PTR_ERR(req); 11499e6268dbSMiklos Szeredi 11509e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 11510e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 1152befc649cSMiklos Szeredi iattr_to_fattr(attr, &inarg); 115349d4914fSMiklos Szeredi if (file) { 115449d4914fSMiklos Szeredi struct fuse_file *ff = file->private_data; 115549d4914fSMiklos Szeredi inarg.valid |= FATTR_FH; 115649d4914fSMiklos Szeredi inarg.fh = ff->fh; 115749d4914fSMiklos Szeredi } 1158f3332114SMiklos Szeredi if (attr->ia_valid & ATTR_SIZE) { 1159f3332114SMiklos Szeredi /* For mandatory locking in truncate */ 1160f3332114SMiklos Szeredi inarg.valid |= FATTR_LOCKOWNER; 1161f3332114SMiklos Szeredi inarg.lock_owner = fuse_lock_owner_id(fc, current->files); 1162f3332114SMiklos Szeredi } 11639e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_SETATTR; 11649e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 11659e6268dbSMiklos Szeredi req->in.numargs = 1; 11669e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 11679e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 11689e6268dbSMiklos Szeredi req->out.numargs = 1; 11690e9663eeSMiklos Szeredi if (fc->minor < 9) 11700e9663eeSMiklos Szeredi req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; 11710e9663eeSMiklos Szeredi else 11729e6268dbSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 11739e6268dbSMiklos Szeredi req->out.args[0].value = &outarg; 11749e6268dbSMiklos Szeredi request_send(fc, req); 11759e6268dbSMiklos Szeredi err = req->out.h.error; 11769e6268dbSMiklos Szeredi fuse_put_request(fc, req); 1177e00d2c2dSMiklos Szeredi if (err) { 1178e00d2c2dSMiklos Szeredi if (err == -EINTR) 1179e00d2c2dSMiklos Szeredi fuse_invalidate_attr(inode); 1180e00d2c2dSMiklos Szeredi return err; 1181e00d2c2dSMiklos Szeredi } 1182e00d2c2dSMiklos Szeredi 11839e6268dbSMiklos Szeredi if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { 11849e6268dbSMiklos Szeredi make_bad_inode(inode); 1185e00d2c2dSMiklos Szeredi return -EIO; 11869e6268dbSMiklos Szeredi } 11879e6268dbSMiklos Szeredi 11881fb69e78SMiklos Szeredi fuse_change_attributes(inode, &outarg.attr, attr_timeout(&outarg), 0); 1189e00d2c2dSMiklos Szeredi return 0; 11909e6268dbSMiklos Szeredi } 11919e6268dbSMiklos Szeredi 119249d4914fSMiklos Szeredi static int fuse_setattr(struct dentry *entry, struct iattr *attr) 119349d4914fSMiklos Szeredi { 119449d4914fSMiklos Szeredi if (attr->ia_valid & ATTR_FILE) 119549d4914fSMiklos Szeredi return fuse_do_setattr(entry, attr, attr->ia_file); 119649d4914fSMiklos Szeredi else 119749d4914fSMiklos Szeredi return fuse_do_setattr(entry, attr, NULL); 119849d4914fSMiklos Szeredi } 119949d4914fSMiklos Szeredi 1200e5e5558eSMiklos Szeredi static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, 1201e5e5558eSMiklos Szeredi struct kstat *stat) 1202e5e5558eSMiklos Szeredi { 1203e5e5558eSMiklos Szeredi struct inode *inode = entry->d_inode; 1204244f6385SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1205244f6385SMiklos Szeredi 1206244f6385SMiklos Szeredi if (!fuse_allow_task(fc, current)) 1207244f6385SMiklos Szeredi return -EACCES; 1208244f6385SMiklos Szeredi 1209bcb4be80SMiklos Szeredi return fuse_update_attributes(inode, stat, NULL, NULL); 1210e5e5558eSMiklos Szeredi } 1211e5e5558eSMiklos Szeredi 121292a8780eSMiklos Szeredi static int fuse_setxattr(struct dentry *entry, const char *name, 121392a8780eSMiklos Szeredi const void *value, size_t size, int flags) 121492a8780eSMiklos Szeredi { 121592a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 121692a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 121792a8780eSMiklos Szeredi struct fuse_req *req; 121892a8780eSMiklos Szeredi struct fuse_setxattr_in inarg; 121992a8780eSMiklos Szeredi int err; 122092a8780eSMiklos Szeredi 122192a8780eSMiklos Szeredi if (fc->no_setxattr) 122292a8780eSMiklos Szeredi return -EOPNOTSUPP; 122392a8780eSMiklos Szeredi 1224ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1225ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1226ce1d5a49SMiklos Szeredi return PTR_ERR(req); 122792a8780eSMiklos Szeredi 122892a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 122992a8780eSMiklos Szeredi inarg.size = size; 123092a8780eSMiklos Szeredi inarg.flags = flags; 123192a8780eSMiklos Szeredi req->in.h.opcode = FUSE_SETXATTR; 123292a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 123392a8780eSMiklos Szeredi req->in.numargs = 3; 123492a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 123592a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 123692a8780eSMiklos Szeredi req->in.args[1].size = strlen(name) + 1; 123792a8780eSMiklos Szeredi req->in.args[1].value = name; 123892a8780eSMiklos Szeredi req->in.args[2].size = size; 123992a8780eSMiklos Szeredi req->in.args[2].value = value; 124092a8780eSMiklos Szeredi request_send(fc, req); 124192a8780eSMiklos Szeredi err = req->out.h.error; 124292a8780eSMiklos Szeredi fuse_put_request(fc, req); 124392a8780eSMiklos Szeredi if (err == -ENOSYS) { 124492a8780eSMiklos Szeredi fc->no_setxattr = 1; 124592a8780eSMiklos Szeredi err = -EOPNOTSUPP; 124692a8780eSMiklos Szeredi } 124792a8780eSMiklos Szeredi return err; 124892a8780eSMiklos Szeredi } 124992a8780eSMiklos Szeredi 125092a8780eSMiklos Szeredi static ssize_t fuse_getxattr(struct dentry *entry, const char *name, 125192a8780eSMiklos Szeredi void *value, size_t size) 125292a8780eSMiklos Szeredi { 125392a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 125492a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 125592a8780eSMiklos Szeredi struct fuse_req *req; 125692a8780eSMiklos Szeredi struct fuse_getxattr_in inarg; 125792a8780eSMiklos Szeredi struct fuse_getxattr_out outarg; 125892a8780eSMiklos Szeredi ssize_t ret; 125992a8780eSMiklos Szeredi 126092a8780eSMiklos Szeredi if (fc->no_getxattr) 126192a8780eSMiklos Szeredi return -EOPNOTSUPP; 126292a8780eSMiklos Szeredi 1263ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1264ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1265ce1d5a49SMiklos Szeredi return PTR_ERR(req); 126692a8780eSMiklos Szeredi 126792a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 126892a8780eSMiklos Szeredi inarg.size = size; 126992a8780eSMiklos Szeredi req->in.h.opcode = FUSE_GETXATTR; 127092a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 127192a8780eSMiklos Szeredi req->in.numargs = 2; 127292a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 127392a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 127492a8780eSMiklos Szeredi req->in.args[1].size = strlen(name) + 1; 127592a8780eSMiklos Szeredi req->in.args[1].value = name; 127692a8780eSMiklos Szeredi /* This is really two different operations rolled into one */ 127792a8780eSMiklos Szeredi req->out.numargs = 1; 127892a8780eSMiklos Szeredi if (size) { 127992a8780eSMiklos Szeredi req->out.argvar = 1; 128092a8780eSMiklos Szeredi req->out.args[0].size = size; 128192a8780eSMiklos Szeredi req->out.args[0].value = value; 128292a8780eSMiklos Szeredi } else { 128392a8780eSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 128492a8780eSMiklos Szeredi req->out.args[0].value = &outarg; 128592a8780eSMiklos Szeredi } 128692a8780eSMiklos Szeredi request_send(fc, req); 128792a8780eSMiklos Szeredi ret = req->out.h.error; 128892a8780eSMiklos Szeredi if (!ret) 128992a8780eSMiklos Szeredi ret = size ? req->out.args[0].size : outarg.size; 129092a8780eSMiklos Szeredi else { 129192a8780eSMiklos Szeredi if (ret == -ENOSYS) { 129292a8780eSMiklos Szeredi fc->no_getxattr = 1; 129392a8780eSMiklos Szeredi ret = -EOPNOTSUPP; 129492a8780eSMiklos Szeredi } 129592a8780eSMiklos Szeredi } 129692a8780eSMiklos Szeredi fuse_put_request(fc, req); 129792a8780eSMiklos Szeredi return ret; 129892a8780eSMiklos Szeredi } 129992a8780eSMiklos Szeredi 130092a8780eSMiklos Szeredi static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) 130192a8780eSMiklos Szeredi { 130292a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 130392a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 130492a8780eSMiklos Szeredi struct fuse_req *req; 130592a8780eSMiklos Szeredi struct fuse_getxattr_in inarg; 130692a8780eSMiklos Szeredi struct fuse_getxattr_out outarg; 130792a8780eSMiklos Szeredi ssize_t ret; 130892a8780eSMiklos Szeredi 1309e57ac683SMiklos Szeredi if (!fuse_allow_task(fc, current)) 1310e57ac683SMiklos Szeredi return -EACCES; 1311e57ac683SMiklos Szeredi 131292a8780eSMiklos Szeredi if (fc->no_listxattr) 131392a8780eSMiklos Szeredi return -EOPNOTSUPP; 131492a8780eSMiklos Szeredi 1315ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1316ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1317ce1d5a49SMiklos Szeredi return PTR_ERR(req); 131892a8780eSMiklos Szeredi 131992a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 132092a8780eSMiklos Szeredi inarg.size = size; 132192a8780eSMiklos Szeredi req->in.h.opcode = FUSE_LISTXATTR; 132292a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 132392a8780eSMiklos Szeredi req->in.numargs = 1; 132492a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 132592a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 132692a8780eSMiklos Szeredi /* This is really two different operations rolled into one */ 132792a8780eSMiklos Szeredi req->out.numargs = 1; 132892a8780eSMiklos Szeredi if (size) { 132992a8780eSMiklos Szeredi req->out.argvar = 1; 133092a8780eSMiklos Szeredi req->out.args[0].size = size; 133192a8780eSMiklos Szeredi req->out.args[0].value = list; 133292a8780eSMiklos Szeredi } else { 133392a8780eSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 133492a8780eSMiklos Szeredi req->out.args[0].value = &outarg; 133592a8780eSMiklos Szeredi } 133692a8780eSMiklos Szeredi request_send(fc, req); 133792a8780eSMiklos Szeredi ret = req->out.h.error; 133892a8780eSMiklos Szeredi if (!ret) 133992a8780eSMiklos Szeredi ret = size ? req->out.args[0].size : outarg.size; 134092a8780eSMiklos Szeredi else { 134192a8780eSMiklos Szeredi if (ret == -ENOSYS) { 134292a8780eSMiklos Szeredi fc->no_listxattr = 1; 134392a8780eSMiklos Szeredi ret = -EOPNOTSUPP; 134492a8780eSMiklos Szeredi } 134592a8780eSMiklos Szeredi } 134692a8780eSMiklos Szeredi fuse_put_request(fc, req); 134792a8780eSMiklos Szeredi return ret; 134892a8780eSMiklos Szeredi } 134992a8780eSMiklos Szeredi 135092a8780eSMiklos Szeredi static int fuse_removexattr(struct dentry *entry, const char *name) 135192a8780eSMiklos Szeredi { 135292a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 135392a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 135492a8780eSMiklos Szeredi struct fuse_req *req; 135592a8780eSMiklos Szeredi int err; 135692a8780eSMiklos Szeredi 135792a8780eSMiklos Szeredi if (fc->no_removexattr) 135892a8780eSMiklos Szeredi return -EOPNOTSUPP; 135992a8780eSMiklos Szeredi 1360ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1361ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1362ce1d5a49SMiklos Szeredi return PTR_ERR(req); 136392a8780eSMiklos Szeredi 136492a8780eSMiklos Szeredi req->in.h.opcode = FUSE_REMOVEXATTR; 136592a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 136692a8780eSMiklos Szeredi req->in.numargs = 1; 136792a8780eSMiklos Szeredi req->in.args[0].size = strlen(name) + 1; 136892a8780eSMiklos Szeredi req->in.args[0].value = name; 136992a8780eSMiklos Szeredi request_send(fc, req); 137092a8780eSMiklos Szeredi err = req->out.h.error; 137192a8780eSMiklos Szeredi fuse_put_request(fc, req); 137292a8780eSMiklos Szeredi if (err == -ENOSYS) { 137392a8780eSMiklos Szeredi fc->no_removexattr = 1; 137492a8780eSMiklos Szeredi err = -EOPNOTSUPP; 137592a8780eSMiklos Szeredi } 137692a8780eSMiklos Szeredi return err; 137792a8780eSMiklos Szeredi } 137892a8780eSMiklos Szeredi 1379754661f1SArjan van de Ven static const struct inode_operations fuse_dir_inode_operations = { 1380e5e5558eSMiklos Szeredi .lookup = fuse_lookup, 13819e6268dbSMiklos Szeredi .mkdir = fuse_mkdir, 13829e6268dbSMiklos Szeredi .symlink = fuse_symlink, 13839e6268dbSMiklos Szeredi .unlink = fuse_unlink, 13849e6268dbSMiklos Szeredi .rmdir = fuse_rmdir, 13859e6268dbSMiklos Szeredi .rename = fuse_rename, 13869e6268dbSMiklos Szeredi .link = fuse_link, 13879e6268dbSMiklos Szeredi .setattr = fuse_setattr, 13889e6268dbSMiklos Szeredi .create = fuse_create, 13899e6268dbSMiklos Szeredi .mknod = fuse_mknod, 1390e5e5558eSMiklos Szeredi .permission = fuse_permission, 1391e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 139292a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 139392a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 139492a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 139592a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 1396e5e5558eSMiklos Szeredi }; 1397e5e5558eSMiklos Szeredi 13984b6f5d20SArjan van de Ven static const struct file_operations fuse_dir_operations = { 1399b6aeadedSMiklos Szeredi .llseek = generic_file_llseek, 1400e5e5558eSMiklos Szeredi .read = generic_read_dir, 1401e5e5558eSMiklos Szeredi .readdir = fuse_readdir, 1402e5e5558eSMiklos Szeredi .open = fuse_dir_open, 1403e5e5558eSMiklos Szeredi .release = fuse_dir_release, 140482547981SMiklos Szeredi .fsync = fuse_dir_fsync, 1405e5e5558eSMiklos Szeredi }; 1406e5e5558eSMiklos Szeredi 1407754661f1SArjan van de Ven static const struct inode_operations fuse_common_inode_operations = { 14089e6268dbSMiklos Szeredi .setattr = fuse_setattr, 1409e5e5558eSMiklos Szeredi .permission = fuse_permission, 1410e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 141192a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 141292a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 141392a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 141492a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 1415e5e5558eSMiklos Szeredi }; 1416e5e5558eSMiklos Szeredi 1417754661f1SArjan van de Ven static const struct inode_operations fuse_symlink_inode_operations = { 14189e6268dbSMiklos Szeredi .setattr = fuse_setattr, 1419e5e5558eSMiklos Szeredi .follow_link = fuse_follow_link, 1420e5e5558eSMiklos Szeredi .put_link = fuse_put_link, 1421e5e5558eSMiklos Szeredi .readlink = generic_readlink, 1422e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 142392a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 142492a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 142592a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 142692a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 1427e5e5558eSMiklos Szeredi }; 1428e5e5558eSMiklos Szeredi 1429e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode) 1430e5e5558eSMiklos Szeredi { 1431e5e5558eSMiklos Szeredi inode->i_op = &fuse_common_inode_operations; 1432e5e5558eSMiklos Szeredi } 1433e5e5558eSMiklos Szeredi 1434e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode) 1435e5e5558eSMiklos Szeredi { 1436e5e5558eSMiklos Szeredi inode->i_op = &fuse_dir_inode_operations; 1437e5e5558eSMiklos Szeredi inode->i_fop = &fuse_dir_operations; 1438e5e5558eSMiklos Szeredi } 1439e5e5558eSMiklos Szeredi 1440e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode) 1441e5e5558eSMiklos Szeredi { 1442e5e5558eSMiklos Szeredi inode->i_op = &fuse_symlink_inode_operations; 1443e5e5558eSMiklos Szeredi } 1444