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 */ 100*dbd561d2SMiklos Szeredi 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 1355c5c5e51SMiklos Szeredi 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 228*dbd561d2SMiklos Szeredi 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 */ 2420de6256dSMiklos Szeredi static struct dentry *fuse_d_add_directory(struct dentry *entry, 2430de6256dSMiklos Szeredi struct inode *inode) 244d2a85164SMiklos Szeredi { 245d2a85164SMiklos Szeredi struct dentry *alias = d_find_alias(inode); 2460de6256dSMiklos Szeredi if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) { 247d2a85164SMiklos Szeredi /* This tries to shrink the subtree below alias */ 248d2a85164SMiklos Szeredi fuse_invalidate_entry(alias); 249d2a85164SMiklos Szeredi dput(alias); 250d2a85164SMiklos Szeredi if (!list_empty(&inode->i_dentry)) 2510de6256dSMiklos Szeredi return ERR_PTR(-EBUSY); 2520de6256dSMiklos Szeredi } else { 2530de6256dSMiklos Szeredi dput(alias); 254d2a85164SMiklos Szeredi } 2550de6256dSMiklos Szeredi return d_splice_alias(inode, entry); 256d2a85164SMiklos Szeredi } 257d2a85164SMiklos Szeredi 2580aa7c699SMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, 2590aa7c699SMiklos Szeredi struct nameidata *nd) 260e5e5558eSMiklos Szeredi { 261e5e5558eSMiklos Szeredi int err; 262e5e5558eSMiklos Szeredi struct fuse_entry_out outarg; 263e5e5558eSMiklos Szeredi struct inode *inode = NULL; 2640de6256dSMiklos Szeredi struct dentry *newent; 265e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 266e5e5558eSMiklos Szeredi struct fuse_req *req; 2672d51013eSMiklos Szeredi struct fuse_req *forget_req; 2681fb69e78SMiklos Szeredi u64 attr_version; 269e5e5558eSMiklos Szeredi 270e5e5558eSMiklos Szeredi if (entry->d_name.len > FUSE_NAME_MAX) 2710aa7c699SMiklos Szeredi return ERR_PTR(-ENAMETOOLONG); 272e5e5558eSMiklos Szeredi 273ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 274ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 275e231c2eeSDavid Howells return ERR_CAST(req); 276e5e5558eSMiklos Szeredi 2772d51013eSMiklos Szeredi forget_req = fuse_get_req(fc); 2782d51013eSMiklos Szeredi if (IS_ERR(forget_req)) { 2792d51013eSMiklos Szeredi fuse_put_request(fc, req); 280e231c2eeSDavid Howells return ERR_CAST(forget_req); 2812d51013eSMiklos Szeredi } 2822d51013eSMiklos Szeredi 2837dca9fd3SMiklos Szeredi attr_version = fuse_get_attr_version(fc); 2841fb69e78SMiklos Szeredi 285e5e5558eSMiklos Szeredi fuse_lookup_init(req, dir, entry, &outarg); 286e5e5558eSMiklos Szeredi request_send(fc, req); 287e5e5558eSMiklos Szeredi err = req->out.h.error; 2882d51013eSMiklos Szeredi fuse_put_request(fc, req); 28950322fe7SMiklos Szeredi /* Zero nodeid is same as -ENOENT, but with valid timeout */ 29050322fe7SMiklos Szeredi if (!err && outarg.nodeid && 291a5bfffacSTimo Savola (invalid_nodeid(outarg.nodeid) || 292a5bfffacSTimo Savola !fuse_valid_type(outarg.attr.mode))) 293ee4e5271SMiklos Szeredi err = -EIO; 2948cbdf1e6SMiklos Szeredi if (!err && outarg.nodeid) { 295e5e5558eSMiklos Szeredi inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 2961fb69e78SMiklos Szeredi &outarg.attr, entry_attr_timeout(&outarg), 2971fb69e78SMiklos Szeredi attr_version); 298e5e5558eSMiklos Szeredi if (!inode) { 2992d51013eSMiklos Szeredi fuse_send_forget(fc, forget_req, outarg.nodeid, 1); 3000aa7c699SMiklos Szeredi return ERR_PTR(-ENOMEM); 301e5e5558eSMiklos Szeredi } 302e5e5558eSMiklos Szeredi } 3032d51013eSMiklos Szeredi fuse_put_request(fc, forget_req); 304e5e5558eSMiklos Szeredi if (err && err != -ENOENT) 3050aa7c699SMiklos Szeredi return ERR_PTR(err); 306e5e5558eSMiklos Szeredi 307d2a85164SMiklos Szeredi if (inode && S_ISDIR(inode->i_mode)) { 308d2a85164SMiklos Szeredi mutex_lock(&fc->inst_mutex); 3090de6256dSMiklos Szeredi newent = fuse_d_add_directory(entry, inode); 310d2a85164SMiklos Szeredi mutex_unlock(&fc->inst_mutex); 3110de6256dSMiklos Szeredi if (IS_ERR(newent)) { 3120aa7c699SMiklos Szeredi iput(inode); 3130de6256dSMiklos Szeredi return newent; 314e5e5558eSMiklos Szeredi } 315d2a85164SMiklos Szeredi } else 3160de6256dSMiklos Szeredi newent = d_splice_alias(inode, entry); 317d2a85164SMiklos Szeredi 3180de6256dSMiklos Szeredi entry = newent ? newent : entry; 319e5e5558eSMiklos Szeredi entry->d_op = &fuse_dentry_operations; 3208cbdf1e6SMiklos Szeredi if (!err) 3211fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outarg); 3228cbdf1e6SMiklos Szeredi else 3238cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 3240de6256dSMiklos Szeredi return newent; 325e5e5558eSMiklos Szeredi } 326e5e5558eSMiklos Szeredi 3276f9f1180SMiklos Szeredi /* 32851eb01e7SMiklos Szeredi * Synchronous release for the case when something goes wrong in CREATE_OPEN 32951eb01e7SMiklos Szeredi */ 33051eb01e7SMiklos Szeredi static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff, 33151eb01e7SMiklos Szeredi u64 nodeid, int flags) 33251eb01e7SMiklos Szeredi { 333c756e0a4SMiklos Szeredi fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE); 334c756e0a4SMiklos Szeredi ff->reserved_req->force = 1; 335c756e0a4SMiklos Szeredi request_send(fc, ff->reserved_req); 336c756e0a4SMiklos Szeredi fuse_put_request(fc, ff->reserved_req); 337c756e0a4SMiklos Szeredi kfree(ff); 33851eb01e7SMiklos Szeredi } 33951eb01e7SMiklos Szeredi 34051eb01e7SMiklos Szeredi /* 3416f9f1180SMiklos Szeredi * Atomic create+open operation 3426f9f1180SMiklos Szeredi * 3436f9f1180SMiklos Szeredi * If the filesystem doesn't support this, then fall back to separate 3446f9f1180SMiklos Szeredi * 'mknod' + 'open' requests. 3456f9f1180SMiklos Szeredi */ 346fd72faacSMiklos Szeredi static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, 347fd72faacSMiklos Szeredi struct nameidata *nd) 348fd72faacSMiklos Szeredi { 349fd72faacSMiklos Szeredi int err; 350fd72faacSMiklos Szeredi struct inode *inode; 351fd72faacSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 352fd72faacSMiklos Szeredi struct fuse_req *req; 35351eb01e7SMiklos Szeredi struct fuse_req *forget_req; 354fd72faacSMiklos Szeredi struct fuse_open_in inarg; 355fd72faacSMiklos Szeredi struct fuse_open_out outopen; 356fd72faacSMiklos Szeredi struct fuse_entry_out outentry; 357fd72faacSMiklos Szeredi struct fuse_file *ff; 358fd72faacSMiklos Szeredi struct file *file; 359fd72faacSMiklos Szeredi int flags = nd->intent.open.flags - 1; 360fd72faacSMiklos Szeredi 361fd72faacSMiklos Szeredi if (fc->no_create) 362ce1d5a49SMiklos Szeredi return -ENOSYS; 363fd72faacSMiklos Szeredi 36451eb01e7SMiklos Szeredi forget_req = fuse_get_req(fc); 36551eb01e7SMiklos Szeredi if (IS_ERR(forget_req)) 36651eb01e7SMiklos Szeredi return PTR_ERR(forget_req); 36751eb01e7SMiklos Szeredi 368ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 36951eb01e7SMiklos Szeredi err = PTR_ERR(req); 370ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 37151eb01e7SMiklos Szeredi goto out_put_forget_req; 372fd72faacSMiklos Szeredi 373ce1d5a49SMiklos Szeredi err = -ENOMEM; 374fd72faacSMiklos Szeredi ff = fuse_file_alloc(); 375fd72faacSMiklos Szeredi if (!ff) 376fd72faacSMiklos Szeredi goto out_put_request; 377fd72faacSMiklos Szeredi 378fd72faacSMiklos Szeredi flags &= ~O_NOCTTY; 379fd72faacSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 3800e9663eeSMiklos Szeredi memset(&outentry, 0, sizeof(outentry)); 381fd72faacSMiklos Szeredi inarg.flags = flags; 382fd72faacSMiklos Szeredi inarg.mode = mode; 383fd72faacSMiklos Szeredi req->in.h.opcode = FUSE_CREATE; 384fd72faacSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 385fd72faacSMiklos Szeredi req->in.numargs = 2; 386fd72faacSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 387fd72faacSMiklos Szeredi req->in.args[0].value = &inarg; 388fd72faacSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 389fd72faacSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 390fd72faacSMiklos Szeredi req->out.numargs = 2; 3910e9663eeSMiklos Szeredi if (fc->minor < 9) 3920e9663eeSMiklos Szeredi req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; 3930e9663eeSMiklos Szeredi else 394fd72faacSMiklos Szeredi req->out.args[0].size = sizeof(outentry); 395fd72faacSMiklos Szeredi req->out.args[0].value = &outentry; 396fd72faacSMiklos Szeredi req->out.args[1].size = sizeof(outopen); 397fd72faacSMiklos Szeredi req->out.args[1].value = &outopen; 398fd72faacSMiklos Szeredi request_send(fc, req); 399fd72faacSMiklos Szeredi err = req->out.h.error; 400fd72faacSMiklos Szeredi if (err) { 401fd72faacSMiklos Szeredi if (err == -ENOSYS) 402fd72faacSMiklos Szeredi fc->no_create = 1; 403fd72faacSMiklos Szeredi goto out_free_ff; 404fd72faacSMiklos Szeredi } 405fd72faacSMiklos Szeredi 406fd72faacSMiklos Szeredi err = -EIO; 4072827d0b2SMiklos Szeredi if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid)) 408fd72faacSMiklos Szeredi goto out_free_ff; 409fd72faacSMiklos Szeredi 41051eb01e7SMiklos Szeredi fuse_put_request(fc, req); 411fd72faacSMiklos Szeredi inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, 4121fb69e78SMiklos Szeredi &outentry.attr, entry_attr_timeout(&outentry), 0); 413fd72faacSMiklos Szeredi if (!inode) { 414fd72faacSMiklos Szeredi flags &= ~(O_CREAT | O_EXCL | O_TRUNC); 415fd72faacSMiklos Szeredi ff->fh = outopen.fh; 41651eb01e7SMiklos Szeredi fuse_sync_release(fc, ff, outentry.nodeid, flags); 41751eb01e7SMiklos Szeredi fuse_send_forget(fc, forget_req, outentry.nodeid, 1); 41851eb01e7SMiklos Szeredi return -ENOMEM; 419fd72faacSMiklos Szeredi } 42051eb01e7SMiklos Szeredi fuse_put_request(fc, forget_req); 421fd72faacSMiklos Szeredi d_instantiate(entry, inode); 4221fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outentry); 4230952b2a4SMiklos Szeredi fuse_invalidate_attr(dir); 424fd72faacSMiklos Szeredi file = lookup_instantiate_filp(nd, entry, generic_file_open); 425fd72faacSMiklos Szeredi if (IS_ERR(file)) { 426fd72faacSMiklos Szeredi ff->fh = outopen.fh; 42751eb01e7SMiklos Szeredi fuse_sync_release(fc, ff, outentry.nodeid, flags); 428fd72faacSMiklos Szeredi return PTR_ERR(file); 429fd72faacSMiklos Szeredi } 430fd72faacSMiklos Szeredi fuse_finish_open(inode, file, ff, &outopen); 431fd72faacSMiklos Szeredi return 0; 432fd72faacSMiklos Szeredi 433fd72faacSMiklos Szeredi out_free_ff: 434fd72faacSMiklos Szeredi fuse_file_free(ff); 435fd72faacSMiklos Szeredi out_put_request: 436fd72faacSMiklos Szeredi fuse_put_request(fc, req); 43751eb01e7SMiklos Szeredi out_put_forget_req: 43851eb01e7SMiklos Szeredi fuse_put_request(fc, forget_req); 439fd72faacSMiklos Szeredi return err; 440fd72faacSMiklos Szeredi } 441fd72faacSMiklos Szeredi 4426f9f1180SMiklos Szeredi /* 4436f9f1180SMiklos Szeredi * Code shared between mknod, mkdir, symlink and link 4446f9f1180SMiklos Szeredi */ 4459e6268dbSMiklos Szeredi static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, 4469e6268dbSMiklos Szeredi struct inode *dir, struct dentry *entry, 4479e6268dbSMiklos Szeredi int mode) 4489e6268dbSMiklos Szeredi { 4499e6268dbSMiklos Szeredi struct fuse_entry_out outarg; 4509e6268dbSMiklos Szeredi struct inode *inode; 4519e6268dbSMiklos Szeredi int err; 4522d51013eSMiklos Szeredi struct fuse_req *forget_req; 4532d51013eSMiklos Szeredi 4542d51013eSMiklos Szeredi forget_req = fuse_get_req(fc); 4552d51013eSMiklos Szeredi if (IS_ERR(forget_req)) { 4562d51013eSMiklos Szeredi fuse_put_request(fc, req); 4572d51013eSMiklos Szeredi return PTR_ERR(forget_req); 4582d51013eSMiklos Szeredi } 4599e6268dbSMiklos Szeredi 4600e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 4619e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 4629e6268dbSMiklos Szeredi req->out.numargs = 1; 4630e9663eeSMiklos Szeredi if (fc->minor < 9) 4640e9663eeSMiklos Szeredi req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; 4650e9663eeSMiklos Szeredi else 4669e6268dbSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 4679e6268dbSMiklos Szeredi req->out.args[0].value = &outarg; 4689e6268dbSMiklos Szeredi request_send(fc, req); 4699e6268dbSMiklos Szeredi err = req->out.h.error; 4709e6268dbSMiklos Szeredi fuse_put_request(fc, req); 4712d51013eSMiklos Szeredi if (err) 4722d51013eSMiklos Szeredi goto out_put_forget_req; 4732d51013eSMiklos Szeredi 47439ee059aSMiklos Szeredi err = -EIO; 47539ee059aSMiklos Szeredi if (invalid_nodeid(outarg.nodeid)) 4762d51013eSMiklos Szeredi goto out_put_forget_req; 47739ee059aSMiklos Szeredi 47839ee059aSMiklos Szeredi if ((outarg.attr.mode ^ mode) & S_IFMT) 4792d51013eSMiklos Szeredi goto out_put_forget_req; 48039ee059aSMiklos Szeredi 4819e6268dbSMiklos Szeredi inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 4821fb69e78SMiklos Szeredi &outarg.attr, entry_attr_timeout(&outarg), 0); 4839e6268dbSMiklos Szeredi if (!inode) { 4842d51013eSMiklos Szeredi fuse_send_forget(fc, forget_req, outarg.nodeid, 1); 4859e6268dbSMiklos Szeredi return -ENOMEM; 4869e6268dbSMiklos Szeredi } 4872d51013eSMiklos Szeredi fuse_put_request(fc, forget_req); 4889e6268dbSMiklos Szeredi 489d2a85164SMiklos Szeredi if (S_ISDIR(inode->i_mode)) { 490d2a85164SMiklos Szeredi struct dentry *alias; 491d2a85164SMiklos Szeredi mutex_lock(&fc->inst_mutex); 492d2a85164SMiklos Szeredi alias = d_find_alias(inode); 493d2a85164SMiklos Szeredi if (alias) { 494d2a85164SMiklos Szeredi /* New directory must have moved since mkdir */ 495d2a85164SMiklos Szeredi mutex_unlock(&fc->inst_mutex); 496d2a85164SMiklos Szeredi dput(alias); 4979e6268dbSMiklos Szeredi iput(inode); 498d2a85164SMiklos Szeredi return -EBUSY; 4999e6268dbSMiklos Szeredi } 5009e6268dbSMiklos Szeredi d_instantiate(entry, inode); 501d2a85164SMiklos Szeredi mutex_unlock(&fc->inst_mutex); 502d2a85164SMiklos Szeredi } else 503d2a85164SMiklos Szeredi d_instantiate(entry, inode); 504d2a85164SMiklos Szeredi 5051fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outarg); 5069e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 5079e6268dbSMiklos Szeredi return 0; 50839ee059aSMiklos Szeredi 5092d51013eSMiklos Szeredi out_put_forget_req: 5102d51013eSMiklos Szeredi fuse_put_request(fc, forget_req); 51139ee059aSMiklos Szeredi return err; 5129e6268dbSMiklos Szeredi } 5139e6268dbSMiklos Szeredi 5149e6268dbSMiklos Szeredi static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, 5159e6268dbSMiklos Szeredi dev_t rdev) 5169e6268dbSMiklos Szeredi { 5179e6268dbSMiklos Szeredi struct fuse_mknod_in inarg; 5189e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 519ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 520ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 521ce1d5a49SMiklos Szeredi return PTR_ERR(req); 5229e6268dbSMiklos Szeredi 5239e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 5249e6268dbSMiklos Szeredi inarg.mode = mode; 5259e6268dbSMiklos Szeredi inarg.rdev = new_encode_dev(rdev); 5269e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_MKNOD; 5279e6268dbSMiklos Szeredi req->in.numargs = 2; 5289e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 5299e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 5309e6268dbSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 5319e6268dbSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 5329e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, mode); 5339e6268dbSMiklos Szeredi } 5349e6268dbSMiklos Szeredi 5359e6268dbSMiklos Szeredi static int fuse_create(struct inode *dir, struct dentry *entry, int mode, 5369e6268dbSMiklos Szeredi struct nameidata *nd) 5379e6268dbSMiklos Szeredi { 538b9ba347fSMiklos Szeredi if (nd && (nd->flags & LOOKUP_OPEN)) { 539fd72faacSMiklos Szeredi int err = fuse_create_open(dir, entry, mode, nd); 540fd72faacSMiklos Szeredi if (err != -ENOSYS) 541fd72faacSMiklos Szeredi return err; 542fd72faacSMiklos Szeredi /* Fall back on mknod */ 543fd72faacSMiklos Szeredi } 5449e6268dbSMiklos Szeredi return fuse_mknod(dir, entry, mode, 0); 5459e6268dbSMiklos Szeredi } 5469e6268dbSMiklos Szeredi 5479e6268dbSMiklos Szeredi static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode) 5489e6268dbSMiklos Szeredi { 5499e6268dbSMiklos Szeredi struct fuse_mkdir_in inarg; 5509e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 551ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 552ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 553ce1d5a49SMiklos Szeredi return PTR_ERR(req); 5549e6268dbSMiklos Szeredi 5559e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 5569e6268dbSMiklos Szeredi inarg.mode = mode; 5579e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_MKDIR; 5589e6268dbSMiklos Szeredi req->in.numargs = 2; 5599e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 5609e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 5619e6268dbSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 5629e6268dbSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 5639e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, S_IFDIR); 5649e6268dbSMiklos Szeredi } 5659e6268dbSMiklos Szeredi 5669e6268dbSMiklos Szeredi static int fuse_symlink(struct inode *dir, struct dentry *entry, 5679e6268dbSMiklos Szeredi const char *link) 5689e6268dbSMiklos Szeredi { 5699e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 5709e6268dbSMiklos Szeredi unsigned len = strlen(link) + 1; 571ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 572ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 573ce1d5a49SMiklos Szeredi return PTR_ERR(req); 5749e6268dbSMiklos Szeredi 5759e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_SYMLINK; 5769e6268dbSMiklos Szeredi req->in.numargs = 2; 5779e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 5789e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 5799e6268dbSMiklos Szeredi req->in.args[1].size = len; 5809e6268dbSMiklos Szeredi req->in.args[1].value = link; 5819e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, S_IFLNK); 5829e6268dbSMiklos Szeredi } 5839e6268dbSMiklos Szeredi 5849e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry) 5859e6268dbSMiklos Szeredi { 5869e6268dbSMiklos Szeredi int err; 5879e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 588ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 589ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 590ce1d5a49SMiklos Szeredi return PTR_ERR(req); 5919e6268dbSMiklos Szeredi 5929e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_UNLINK; 5939e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 5949e6268dbSMiklos Szeredi req->in.numargs = 1; 5959e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 5969e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 5979e6268dbSMiklos Szeredi request_send(fc, req); 5989e6268dbSMiklos Szeredi err = req->out.h.error; 5999e6268dbSMiklos Szeredi fuse_put_request(fc, req); 6009e6268dbSMiklos Szeredi if (!err) { 6019e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 6029e6268dbSMiklos Szeredi 6039e6268dbSMiklos Szeredi /* Set nlink to zero so the inode can be cleared, if 6049e6268dbSMiklos Szeredi the inode does have more links this will be 6059e6268dbSMiklos Szeredi discovered at the next lookup/getattr */ 606ce71ec36SDave Hansen clear_nlink(inode); 6079e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 6089e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 6098cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 6109e6268dbSMiklos Szeredi } else if (err == -EINTR) 6119e6268dbSMiklos Szeredi fuse_invalidate_entry(entry); 6129e6268dbSMiklos Szeredi return err; 6139e6268dbSMiklos Szeredi } 6149e6268dbSMiklos Szeredi 6159e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry) 6169e6268dbSMiklos Szeredi { 6179e6268dbSMiklos Szeredi int err; 6189e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 619ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 620ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 621ce1d5a49SMiklos Szeredi return PTR_ERR(req); 6229e6268dbSMiklos Szeredi 6239e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_RMDIR; 6249e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 6259e6268dbSMiklos Szeredi req->in.numargs = 1; 6269e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 6279e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 6289e6268dbSMiklos Szeredi request_send(fc, req); 6299e6268dbSMiklos Szeredi err = req->out.h.error; 6309e6268dbSMiklos Szeredi fuse_put_request(fc, req); 6319e6268dbSMiklos Szeredi if (!err) { 632ce71ec36SDave Hansen clear_nlink(entry->d_inode); 6339e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 6348cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 6359e6268dbSMiklos Szeredi } else if (err == -EINTR) 6369e6268dbSMiklos Szeredi fuse_invalidate_entry(entry); 6379e6268dbSMiklos Szeredi return err; 6389e6268dbSMiklos Szeredi } 6399e6268dbSMiklos Szeredi 6409e6268dbSMiklos Szeredi static int fuse_rename(struct inode *olddir, struct dentry *oldent, 6419e6268dbSMiklos Szeredi struct inode *newdir, struct dentry *newent) 6429e6268dbSMiklos Szeredi { 6439e6268dbSMiklos Szeredi int err; 6449e6268dbSMiklos Szeredi struct fuse_rename_in inarg; 6459e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(olddir); 646ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 647ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 648ce1d5a49SMiklos Szeredi return PTR_ERR(req); 6499e6268dbSMiklos Szeredi 6509e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 6519e6268dbSMiklos Szeredi inarg.newdir = get_node_id(newdir); 6529e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_RENAME; 6539e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(olddir); 6549e6268dbSMiklos Szeredi req->in.numargs = 3; 6559e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 6569e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 6579e6268dbSMiklos Szeredi req->in.args[1].size = oldent->d_name.len + 1; 6589e6268dbSMiklos Szeredi req->in.args[1].value = oldent->d_name.name; 6599e6268dbSMiklos Szeredi req->in.args[2].size = newent->d_name.len + 1; 6609e6268dbSMiklos Szeredi req->in.args[2].value = newent->d_name.name; 6619e6268dbSMiklos Szeredi request_send(fc, req); 6629e6268dbSMiklos Szeredi err = req->out.h.error; 6639e6268dbSMiklos Szeredi fuse_put_request(fc, req); 6649e6268dbSMiklos Szeredi if (!err) { 66508b63307SMiklos Szeredi /* ctime changes */ 66608b63307SMiklos Szeredi fuse_invalidate_attr(oldent->d_inode); 66708b63307SMiklos Szeredi 6689e6268dbSMiklos Szeredi fuse_invalidate_attr(olddir); 6699e6268dbSMiklos Szeredi if (olddir != newdir) 6709e6268dbSMiklos Szeredi fuse_invalidate_attr(newdir); 6718cbdf1e6SMiklos Szeredi 6728cbdf1e6SMiklos Szeredi /* newent will end up negative */ 6738cbdf1e6SMiklos Szeredi if (newent->d_inode) 6748cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(newent); 6759e6268dbSMiklos Szeredi } else if (err == -EINTR) { 6769e6268dbSMiklos Szeredi /* If request was interrupted, DEITY only knows if the 6779e6268dbSMiklos Szeredi rename actually took place. If the invalidation 6789e6268dbSMiklos Szeredi fails (e.g. some process has CWD under the renamed 6799e6268dbSMiklos Szeredi directory), then there can be inconsistency between 6809e6268dbSMiklos Szeredi the dcache and the real filesystem. Tough luck. */ 6819e6268dbSMiklos Szeredi fuse_invalidate_entry(oldent); 6829e6268dbSMiklos Szeredi if (newent->d_inode) 6839e6268dbSMiklos Szeredi fuse_invalidate_entry(newent); 6849e6268dbSMiklos Szeredi } 6859e6268dbSMiklos Szeredi 6869e6268dbSMiklos Szeredi return err; 6879e6268dbSMiklos Szeredi } 6889e6268dbSMiklos Szeredi 6899e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir, 6909e6268dbSMiklos Szeredi struct dentry *newent) 6919e6268dbSMiklos Szeredi { 6929e6268dbSMiklos Szeredi int err; 6939e6268dbSMiklos Szeredi struct fuse_link_in inarg; 6949e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 6959e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 696ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 697ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 698ce1d5a49SMiklos Szeredi return PTR_ERR(req); 6999e6268dbSMiklos Szeredi 7009e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 7019e6268dbSMiklos Szeredi inarg.oldnodeid = get_node_id(inode); 7029e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_LINK; 7039e6268dbSMiklos Szeredi req->in.numargs = 2; 7049e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 7059e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 7069e6268dbSMiklos Szeredi req->in.args[1].size = newent->d_name.len + 1; 7079e6268dbSMiklos Szeredi req->in.args[1].value = newent->d_name.name; 7089e6268dbSMiklos Szeredi err = create_new_entry(fc, req, newdir, newent, inode->i_mode); 7099e6268dbSMiklos Szeredi /* Contrary to "normal" filesystems it can happen that link 7109e6268dbSMiklos Szeredi makes two "logical" inodes point to the same "physical" 7119e6268dbSMiklos Szeredi inode. We invalidate the attributes of the old one, so it 7129e6268dbSMiklos Szeredi will reflect changes in the backing inode (link count, 7139e6268dbSMiklos Szeredi etc.) 7149e6268dbSMiklos Szeredi */ 7159e6268dbSMiklos Szeredi if (!err || err == -EINTR) 7169e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 7179e6268dbSMiklos Szeredi return err; 7189e6268dbSMiklos Szeredi } 7199e6268dbSMiklos Szeredi 7201fb69e78SMiklos Szeredi static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, 7211fb69e78SMiklos Szeredi struct kstat *stat) 7221fb69e78SMiklos Szeredi { 7231fb69e78SMiklos Szeredi stat->dev = inode->i_sb->s_dev; 7241fb69e78SMiklos Szeredi stat->ino = attr->ino; 7251fb69e78SMiklos Szeredi stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); 7261fb69e78SMiklos Szeredi stat->nlink = attr->nlink; 7271fb69e78SMiklos Szeredi stat->uid = attr->uid; 7281fb69e78SMiklos Szeredi stat->gid = attr->gid; 7291fb69e78SMiklos Szeredi stat->rdev = inode->i_rdev; 7301fb69e78SMiklos Szeredi stat->atime.tv_sec = attr->atime; 7311fb69e78SMiklos Szeredi stat->atime.tv_nsec = attr->atimensec; 7321fb69e78SMiklos Szeredi stat->mtime.tv_sec = attr->mtime; 7331fb69e78SMiklos Szeredi stat->mtime.tv_nsec = attr->mtimensec; 7341fb69e78SMiklos Szeredi stat->ctime.tv_sec = attr->ctime; 7351fb69e78SMiklos Szeredi stat->ctime.tv_nsec = attr->ctimensec; 7361fb69e78SMiklos Szeredi stat->size = attr->size; 7371fb69e78SMiklos Szeredi stat->blocks = attr->blocks; 7381fb69e78SMiklos Szeredi stat->blksize = (1 << inode->i_blkbits); 7391fb69e78SMiklos Szeredi } 7401fb69e78SMiklos Szeredi 741c79e322fSMiklos Szeredi static int fuse_do_getattr(struct inode *inode, struct kstat *stat, 742c79e322fSMiklos Szeredi struct file *file) 743e5e5558eSMiklos Szeredi { 744e5e5558eSMiklos Szeredi int err; 745c79e322fSMiklos Szeredi struct fuse_getattr_in inarg; 746c79e322fSMiklos Szeredi struct fuse_attr_out outarg; 747e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 7481fb69e78SMiklos Szeredi struct fuse_req *req; 7491fb69e78SMiklos Szeredi u64 attr_version; 7501fb69e78SMiklos Szeredi 7511fb69e78SMiklos Szeredi req = fuse_get_req(fc); 752ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 753ce1d5a49SMiklos Szeredi return PTR_ERR(req); 754e5e5558eSMiklos Szeredi 7557dca9fd3SMiklos Szeredi attr_version = fuse_get_attr_version(fc); 7561fb69e78SMiklos Szeredi 757c79e322fSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 7580e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 759c79e322fSMiklos Szeredi /* Directories have separate file-handle space */ 760c79e322fSMiklos Szeredi if (file && S_ISREG(inode->i_mode)) { 761c79e322fSMiklos Szeredi struct fuse_file *ff = file->private_data; 762c79e322fSMiklos Szeredi 763c79e322fSMiklos Szeredi inarg.getattr_flags |= FUSE_GETATTR_FH; 764c79e322fSMiklos Szeredi inarg.fh = ff->fh; 765c79e322fSMiklos Szeredi } 766e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_GETATTR; 767e5e5558eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 768c79e322fSMiklos Szeredi req->in.numargs = 1; 769c79e322fSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 770c79e322fSMiklos Szeredi req->in.args[0].value = &inarg; 771e5e5558eSMiklos Szeredi req->out.numargs = 1; 7720e9663eeSMiklos Szeredi if (fc->minor < 9) 7730e9663eeSMiklos Szeredi req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; 7740e9663eeSMiklos Szeredi else 775c79e322fSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 776c79e322fSMiklos Szeredi req->out.args[0].value = &outarg; 777e5e5558eSMiklos Szeredi request_send(fc, req); 778e5e5558eSMiklos Szeredi err = req->out.h.error; 779e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 780e5e5558eSMiklos Szeredi if (!err) { 781c79e322fSMiklos Szeredi if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { 782e5e5558eSMiklos Szeredi make_bad_inode(inode); 783e5e5558eSMiklos Szeredi err = -EIO; 784e5e5558eSMiklos Szeredi } else { 785c79e322fSMiklos Szeredi fuse_change_attributes(inode, &outarg.attr, 786c79e322fSMiklos Szeredi attr_timeout(&outarg), 7871fb69e78SMiklos Szeredi attr_version); 7881fb69e78SMiklos Szeredi if (stat) 789c79e322fSMiklos Szeredi fuse_fillattr(inode, &outarg.attr, stat); 790e5e5558eSMiklos Szeredi } 791e5e5558eSMiklos Szeredi } 792e5e5558eSMiklos Szeredi return err; 793e5e5558eSMiklos Szeredi } 794e5e5558eSMiklos Szeredi 795bcb4be80SMiklos Szeredi int fuse_update_attributes(struct inode *inode, struct kstat *stat, 796bcb4be80SMiklos Szeredi struct file *file, bool *refreshed) 797bcb4be80SMiklos Szeredi { 798bcb4be80SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 799bcb4be80SMiklos Szeredi int err; 800bcb4be80SMiklos Szeredi bool r; 801bcb4be80SMiklos Szeredi 802bcb4be80SMiklos Szeredi if (fi->i_time < get_jiffies_64()) { 803bcb4be80SMiklos Szeredi r = true; 804bcb4be80SMiklos Szeredi err = fuse_do_getattr(inode, stat, file); 805bcb4be80SMiklos Szeredi } else { 806bcb4be80SMiklos Szeredi r = false; 807bcb4be80SMiklos Szeredi err = 0; 808bcb4be80SMiklos Szeredi if (stat) { 809bcb4be80SMiklos Szeredi generic_fillattr(inode, stat); 810bcb4be80SMiklos Szeredi stat->mode = fi->orig_i_mode; 811bcb4be80SMiklos Szeredi } 812bcb4be80SMiklos Szeredi } 813bcb4be80SMiklos Szeredi 814bcb4be80SMiklos Szeredi if (refreshed != NULL) 815bcb4be80SMiklos Szeredi *refreshed = r; 816bcb4be80SMiklos Szeredi 817bcb4be80SMiklos Szeredi return err; 818bcb4be80SMiklos Szeredi } 819bcb4be80SMiklos Szeredi 82087729a55SMiklos Szeredi /* 82187729a55SMiklos Szeredi * Calling into a user-controlled filesystem gives the filesystem 82287729a55SMiklos Szeredi * daemon ptrace-like capabilities over the requester process. This 82387729a55SMiklos Szeredi * means, that the filesystem daemon is able to record the exact 82487729a55SMiklos Szeredi * filesystem operations performed, and can also control the behavior 82587729a55SMiklos Szeredi * of the requester process in otherwise impossible ways. For example 82687729a55SMiklos Szeredi * it can delay the operation for arbitrary length of time allowing 82787729a55SMiklos Szeredi * DoS against the requester. 82887729a55SMiklos Szeredi * 82987729a55SMiklos Szeredi * For this reason only those processes can call into the filesystem, 83087729a55SMiklos Szeredi * for which the owner of the mount has ptrace privilege. This 83187729a55SMiklos Szeredi * excludes processes started by other users, suid or sgid processes. 83287729a55SMiklos Szeredi */ 833e57ac683SMiklos Szeredi int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task) 83487729a55SMiklos Szeredi { 83587729a55SMiklos Szeredi if (fc->flags & FUSE_ALLOW_OTHER) 83687729a55SMiklos Szeredi return 1; 83787729a55SMiklos Szeredi 83887729a55SMiklos Szeredi if (task->euid == fc->user_id && 83987729a55SMiklos Szeredi task->suid == fc->user_id && 84087729a55SMiklos Szeredi task->uid == fc->user_id && 84187729a55SMiklos Szeredi task->egid == fc->group_id && 84287729a55SMiklos Szeredi task->sgid == fc->group_id && 84387729a55SMiklos Szeredi task->gid == fc->group_id) 84487729a55SMiklos Szeredi return 1; 84587729a55SMiklos Szeredi 84687729a55SMiklos Szeredi return 0; 84787729a55SMiklos Szeredi } 84887729a55SMiklos Szeredi 84931d40d74SMiklos Szeredi static int fuse_access(struct inode *inode, int mask) 85031d40d74SMiklos Szeredi { 85131d40d74SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 85231d40d74SMiklos Szeredi struct fuse_req *req; 85331d40d74SMiklos Szeredi struct fuse_access_in inarg; 85431d40d74SMiklos Szeredi int err; 85531d40d74SMiklos Szeredi 85631d40d74SMiklos Szeredi if (fc->no_access) 85731d40d74SMiklos Szeredi return 0; 85831d40d74SMiklos Szeredi 859ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 860ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 861ce1d5a49SMiklos Szeredi return PTR_ERR(req); 86231d40d74SMiklos Szeredi 86331d40d74SMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 86431d40d74SMiklos Szeredi inarg.mask = mask; 86531d40d74SMiklos Szeredi req->in.h.opcode = FUSE_ACCESS; 86631d40d74SMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 86731d40d74SMiklos Szeredi req->in.numargs = 1; 86831d40d74SMiklos Szeredi req->in.args[0].size = sizeof(inarg); 86931d40d74SMiklos Szeredi req->in.args[0].value = &inarg; 87031d40d74SMiklos Szeredi request_send(fc, req); 87131d40d74SMiklos Szeredi err = req->out.h.error; 87231d40d74SMiklos Szeredi fuse_put_request(fc, req); 87331d40d74SMiklos Szeredi if (err == -ENOSYS) { 87431d40d74SMiklos Szeredi fc->no_access = 1; 87531d40d74SMiklos Szeredi err = 0; 87631d40d74SMiklos Szeredi } 87731d40d74SMiklos Szeredi return err; 87831d40d74SMiklos Szeredi } 87931d40d74SMiklos Szeredi 8806f9f1180SMiklos Szeredi /* 8816f9f1180SMiklos Szeredi * Check permission. The two basic access models of FUSE are: 8826f9f1180SMiklos Szeredi * 8836f9f1180SMiklos Szeredi * 1) Local access checking ('default_permissions' mount option) based 8846f9f1180SMiklos Szeredi * on file mode. This is the plain old disk filesystem permission 8856f9f1180SMiklos Szeredi * modell. 8866f9f1180SMiklos Szeredi * 8876f9f1180SMiklos Szeredi * 2) "Remote" access checking, where server is responsible for 8886f9f1180SMiklos Szeredi * checking permission in each inode operation. An exception to this 8896f9f1180SMiklos Szeredi * is if ->permission() was invoked from sys_access() in which case an 8906f9f1180SMiklos Szeredi * access request is sent. Execute permission is still checked 8916f9f1180SMiklos Szeredi * locally based on file mode. 8926f9f1180SMiklos Szeredi */ 893e5e5558eSMiklos Szeredi static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) 894e5e5558eSMiklos Szeredi { 895e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 896244f6385SMiklos Szeredi bool refreshed = false; 897244f6385SMiklos Szeredi int err = 0; 898e5e5558eSMiklos Szeredi 89987729a55SMiklos Szeredi if (!fuse_allow_task(fc, current)) 900e5e5558eSMiklos Szeredi return -EACCES; 901244f6385SMiklos Szeredi 902244f6385SMiklos Szeredi /* 903e8e96157SMiklos Szeredi * If attributes are needed, refresh them before proceeding 904244f6385SMiklos Szeredi */ 905e8e96157SMiklos Szeredi if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) || 906e8e96157SMiklos Szeredi ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { 907bcb4be80SMiklos Szeredi err = fuse_update_attributes(inode, NULL, NULL, &refreshed); 908244f6385SMiklos Szeredi if (err) 909244f6385SMiklos Szeredi return err; 9101fb69e78SMiklos Szeredi } 911244f6385SMiklos Szeredi 912244f6385SMiklos Szeredi if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 9131a823ac9SMiklos Szeredi err = generic_permission(inode, mask, NULL); 9141e9a4ed9SMiklos Szeredi 9151e9a4ed9SMiklos Szeredi /* If permission is denied, try to refresh file 9161e9a4ed9SMiklos Szeredi attributes. This is also needed, because the root 9171e9a4ed9SMiklos Szeredi node will at first have no permissions */ 918244f6385SMiklos Szeredi if (err == -EACCES && !refreshed) { 919c79e322fSMiklos Szeredi err = fuse_do_getattr(inode, NULL, NULL); 9201e9a4ed9SMiklos Szeredi if (!err) 9211e9a4ed9SMiklos Szeredi err = generic_permission(inode, mask, NULL); 9221e9a4ed9SMiklos Szeredi } 9231e9a4ed9SMiklos Szeredi 9246f9f1180SMiklos Szeredi /* Note: the opposite of the above test does not 9256f9f1180SMiklos Szeredi exist. So if permissions are revoked this won't be 9266f9f1180SMiklos Szeredi noticed immediately, only after the attribute 9276f9f1180SMiklos Szeredi timeout has expired */ 928e8e96157SMiklos Szeredi } else if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR))) { 929e8e96157SMiklos Szeredi err = fuse_access(inode, mask); 930e8e96157SMiklos Szeredi } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { 931e8e96157SMiklos Szeredi if (!(inode->i_mode & S_IXUGO)) { 932e8e96157SMiklos Szeredi if (refreshed) 933e5e5558eSMiklos Szeredi return -EACCES; 93431d40d74SMiklos Szeredi 935c79e322fSMiklos Szeredi err = fuse_do_getattr(inode, NULL, NULL); 936e8e96157SMiklos Szeredi if (!err && !(inode->i_mode & S_IXUGO)) 937e8e96157SMiklos Szeredi return -EACCES; 938e8e96157SMiklos Szeredi } 939e5e5558eSMiklos Szeredi } 940244f6385SMiklos Szeredi return err; 941e5e5558eSMiklos Szeredi } 942e5e5558eSMiklos Szeredi 943e5e5558eSMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file, 944e5e5558eSMiklos Szeredi void *dstbuf, filldir_t filldir) 945e5e5558eSMiklos Szeredi { 946e5e5558eSMiklos Szeredi while (nbytes >= FUSE_NAME_OFFSET) { 947e5e5558eSMiklos Szeredi struct fuse_dirent *dirent = (struct fuse_dirent *) buf; 948e5e5558eSMiklos Szeredi size_t reclen = FUSE_DIRENT_SIZE(dirent); 949e5e5558eSMiklos Szeredi int over; 950e5e5558eSMiklos Szeredi if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) 951e5e5558eSMiklos Szeredi return -EIO; 952e5e5558eSMiklos Szeredi if (reclen > nbytes) 953e5e5558eSMiklos Szeredi break; 954e5e5558eSMiklos Szeredi 955e5e5558eSMiklos Szeredi over = filldir(dstbuf, dirent->name, dirent->namelen, 956e5e5558eSMiklos Szeredi file->f_pos, dirent->ino, dirent->type); 957e5e5558eSMiklos Szeredi if (over) 958e5e5558eSMiklos Szeredi break; 959e5e5558eSMiklos Szeredi 960e5e5558eSMiklos Szeredi buf += reclen; 961e5e5558eSMiklos Szeredi nbytes -= reclen; 962e5e5558eSMiklos Szeredi file->f_pos = dirent->off; 963e5e5558eSMiklos Szeredi } 964e5e5558eSMiklos Szeredi 965e5e5558eSMiklos Szeredi return 0; 966e5e5558eSMiklos Szeredi } 967e5e5558eSMiklos Szeredi 968e5e5558eSMiklos Szeredi static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) 969e5e5558eSMiklos Szeredi { 97004730fefSMiklos Szeredi int err; 97104730fefSMiklos Szeredi size_t nbytes; 97204730fefSMiklos Szeredi struct page *page; 9737706a9d6SJosef Sipek struct inode *inode = file->f_path.dentry->d_inode; 97404730fefSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 975248d86e8SMiklos Szeredi struct fuse_req *req; 976248d86e8SMiklos Szeredi 977248d86e8SMiklos Szeredi if (is_bad_inode(inode)) 978248d86e8SMiklos Szeredi return -EIO; 979248d86e8SMiklos Szeredi 980ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 981ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 982ce1d5a49SMiklos Szeredi return PTR_ERR(req); 983e5e5558eSMiklos Szeredi 98404730fefSMiklos Szeredi page = alloc_page(GFP_KERNEL); 98504730fefSMiklos Szeredi if (!page) { 98604730fefSMiklos Szeredi fuse_put_request(fc, req); 987e5e5558eSMiklos Szeredi return -ENOMEM; 98804730fefSMiklos Szeredi } 98904730fefSMiklos Szeredi req->num_pages = 1; 99004730fefSMiklos Szeredi req->pages[0] = page; 991a6643094SMiklos Szeredi fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR); 992361b1eb5SMiklos Szeredi request_send(fc, req); 993361b1eb5SMiklos Szeredi nbytes = req->out.args[0].size; 99404730fefSMiklos Szeredi err = req->out.h.error; 99504730fefSMiklos Szeredi fuse_put_request(fc, req); 99604730fefSMiklos Szeredi if (!err) 99704730fefSMiklos Szeredi err = parse_dirfile(page_address(page), nbytes, file, dstbuf, 99804730fefSMiklos Szeredi filldir); 999e5e5558eSMiklos Szeredi 100004730fefSMiklos Szeredi __free_page(page); 1001b36c31baSMiklos Szeredi fuse_invalidate_attr(inode); /* atime changed */ 100204730fefSMiklos Szeredi return err; 1003e5e5558eSMiklos Szeredi } 1004e5e5558eSMiklos Szeredi 1005e5e5558eSMiklos Szeredi static char *read_link(struct dentry *dentry) 1006e5e5558eSMiklos Szeredi { 1007e5e5558eSMiklos Szeredi struct inode *inode = dentry->d_inode; 1008e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1009ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 1010e5e5558eSMiklos Szeredi char *link; 1011e5e5558eSMiklos Szeredi 1012ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1013e231c2eeSDavid Howells return ERR_CAST(req); 1014e5e5558eSMiklos Szeredi 1015e5e5558eSMiklos Szeredi link = (char *) __get_free_page(GFP_KERNEL); 1016e5e5558eSMiklos Szeredi if (!link) { 1017e5e5558eSMiklos Szeredi link = ERR_PTR(-ENOMEM); 1018e5e5558eSMiklos Szeredi goto out; 1019e5e5558eSMiklos Szeredi } 1020e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_READLINK; 1021e5e5558eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 1022e5e5558eSMiklos Szeredi req->out.argvar = 1; 1023e5e5558eSMiklos Szeredi req->out.numargs = 1; 1024e5e5558eSMiklos Szeredi req->out.args[0].size = PAGE_SIZE - 1; 1025e5e5558eSMiklos Szeredi req->out.args[0].value = link; 1026e5e5558eSMiklos Szeredi request_send(fc, req); 1027e5e5558eSMiklos Szeredi if (req->out.h.error) { 1028e5e5558eSMiklos Szeredi free_page((unsigned long) link); 1029e5e5558eSMiklos Szeredi link = ERR_PTR(req->out.h.error); 1030e5e5558eSMiklos Szeredi } else 1031e5e5558eSMiklos Szeredi link[req->out.args[0].size] = '\0'; 1032e5e5558eSMiklos Szeredi out: 1033e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 1034b36c31baSMiklos Szeredi fuse_invalidate_attr(inode); /* atime changed */ 1035e5e5558eSMiklos Szeredi return link; 1036e5e5558eSMiklos Szeredi } 1037e5e5558eSMiklos Szeredi 1038e5e5558eSMiklos Szeredi static void free_link(char *link) 1039e5e5558eSMiklos Szeredi { 1040e5e5558eSMiklos Szeredi if (!IS_ERR(link)) 1041e5e5558eSMiklos Szeredi free_page((unsigned long) link); 1042e5e5558eSMiklos Szeredi } 1043e5e5558eSMiklos Szeredi 1044e5e5558eSMiklos Szeredi static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd) 1045e5e5558eSMiklos Szeredi { 1046e5e5558eSMiklos Szeredi nd_set_link(nd, read_link(dentry)); 1047e5e5558eSMiklos Szeredi return NULL; 1048e5e5558eSMiklos Szeredi } 1049e5e5558eSMiklos Szeredi 1050e5e5558eSMiklos Szeredi static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c) 1051e5e5558eSMiklos Szeredi { 1052e5e5558eSMiklos Szeredi free_link(nd_get_link(nd)); 1053e5e5558eSMiklos Szeredi } 1054e5e5558eSMiklos Szeredi 1055e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file) 1056e5e5558eSMiklos Szeredi { 105704730fefSMiklos Szeredi return fuse_open_common(inode, file, 1); 1058e5e5558eSMiklos Szeredi } 1059e5e5558eSMiklos Szeredi 1060e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file) 1061e5e5558eSMiklos Szeredi { 106204730fefSMiklos Szeredi return fuse_release_common(inode, file, 1); 1063e5e5558eSMiklos Szeredi } 1064e5e5558eSMiklos Szeredi 106582547981SMiklos Szeredi static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync) 106682547981SMiklos Szeredi { 106782547981SMiklos Szeredi /* nfsd can call this with no file */ 106882547981SMiklos Szeredi return file ? fuse_fsync_common(file, de, datasync, 1) : 0; 106982547981SMiklos Szeredi } 107082547981SMiklos Szeredi 107117637cbaSMiklos Szeredi static bool update_mtime(unsigned ivalid) 107217637cbaSMiklos Szeredi { 107317637cbaSMiklos Szeredi /* Always update if mtime is explicitly set */ 107417637cbaSMiklos Szeredi if (ivalid & ATTR_MTIME_SET) 107517637cbaSMiklos Szeredi return true; 107617637cbaSMiklos Szeredi 107717637cbaSMiklos Szeredi /* If it's an open(O_TRUNC) or an ftruncate(), don't update */ 107817637cbaSMiklos Szeredi if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE))) 107917637cbaSMiklos Szeredi return false; 108017637cbaSMiklos Szeredi 108117637cbaSMiklos Szeredi /* In all other cases update */ 108217637cbaSMiklos Szeredi return true; 108317637cbaSMiklos Szeredi } 108417637cbaSMiklos Szeredi 1085befc649cSMiklos Szeredi static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) 10869e6268dbSMiklos Szeredi { 10879e6268dbSMiklos Szeredi unsigned ivalid = iattr->ia_valid; 10889e6268dbSMiklos Szeredi 10899e6268dbSMiklos Szeredi if (ivalid & ATTR_MODE) 1090befc649cSMiklos Szeredi arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode; 10919e6268dbSMiklos Szeredi if (ivalid & ATTR_UID) 1092befc649cSMiklos Szeredi arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid; 10939e6268dbSMiklos Szeredi if (ivalid & ATTR_GID) 1094befc649cSMiklos Szeredi arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid; 10959e6268dbSMiklos Szeredi if (ivalid & ATTR_SIZE) 1096befc649cSMiklos Szeredi arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size; 109717637cbaSMiklos Szeredi if (ivalid & ATTR_ATIME) { 109817637cbaSMiklos Szeredi arg->valid |= FATTR_ATIME; 1099befc649cSMiklos Szeredi arg->atime = iattr->ia_atime.tv_sec; 110017637cbaSMiklos Szeredi arg->atimensec = iattr->ia_atime.tv_nsec; 110117637cbaSMiklos Szeredi if (!(ivalid & ATTR_ATIME_SET)) 110217637cbaSMiklos Szeredi arg->valid |= FATTR_ATIME_NOW; 110317637cbaSMiklos Szeredi } 110417637cbaSMiklos Szeredi if ((ivalid & ATTR_MTIME) && update_mtime(ivalid)) { 110517637cbaSMiklos Szeredi arg->valid |= FATTR_MTIME; 1106befc649cSMiklos Szeredi arg->mtime = iattr->ia_mtime.tv_sec; 110717637cbaSMiklos Szeredi arg->mtimensec = iattr->ia_mtime.tv_nsec; 110817637cbaSMiklos Szeredi if (!(ivalid & ATTR_MTIME_SET)) 110917637cbaSMiklos Szeredi arg->valid |= FATTR_MTIME_NOW; 11109e6268dbSMiklos Szeredi } 11119e6268dbSMiklos Szeredi } 11129e6268dbSMiklos Szeredi 11136f9f1180SMiklos Szeredi /* 11143be5a52bSMiklos Szeredi * Prevent concurrent writepages on inode 11153be5a52bSMiklos Szeredi * 11163be5a52bSMiklos Szeredi * This is done by adding a negative bias to the inode write counter 11173be5a52bSMiklos Szeredi * and waiting for all pending writes to finish. 11183be5a52bSMiklos Szeredi */ 11193be5a52bSMiklos Szeredi void fuse_set_nowrite(struct inode *inode) 11203be5a52bSMiklos Szeredi { 11213be5a52bSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 11223be5a52bSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 11233be5a52bSMiklos Szeredi 11243be5a52bSMiklos Szeredi BUG_ON(!mutex_is_locked(&inode->i_mutex)); 11253be5a52bSMiklos Szeredi 11263be5a52bSMiklos Szeredi spin_lock(&fc->lock); 11273be5a52bSMiklos Szeredi BUG_ON(fi->writectr < 0); 11283be5a52bSMiklos Szeredi fi->writectr += FUSE_NOWRITE; 11293be5a52bSMiklos Szeredi spin_unlock(&fc->lock); 11303be5a52bSMiklos Szeredi wait_event(fi->page_waitq, fi->writectr == FUSE_NOWRITE); 11313be5a52bSMiklos Szeredi } 11323be5a52bSMiklos Szeredi 11333be5a52bSMiklos Szeredi /* 11343be5a52bSMiklos Szeredi * Allow writepages on inode 11353be5a52bSMiklos Szeredi * 11363be5a52bSMiklos Szeredi * Remove the bias from the writecounter and send any queued 11373be5a52bSMiklos Szeredi * writepages. 11383be5a52bSMiklos Szeredi */ 11393be5a52bSMiklos Szeredi static void __fuse_release_nowrite(struct inode *inode) 11403be5a52bSMiklos Szeredi { 11413be5a52bSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 11423be5a52bSMiklos Szeredi 11433be5a52bSMiklos Szeredi BUG_ON(fi->writectr != FUSE_NOWRITE); 11443be5a52bSMiklos Szeredi fi->writectr = 0; 11453be5a52bSMiklos Szeredi fuse_flush_writepages(inode); 11463be5a52bSMiklos Szeredi } 11473be5a52bSMiklos Szeredi 11483be5a52bSMiklos Szeredi void fuse_release_nowrite(struct inode *inode) 11493be5a52bSMiklos Szeredi { 11503be5a52bSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 11513be5a52bSMiklos Szeredi 11523be5a52bSMiklos Szeredi spin_lock(&fc->lock); 11533be5a52bSMiklos Szeredi __fuse_release_nowrite(inode); 11543be5a52bSMiklos Szeredi spin_unlock(&fc->lock); 11553be5a52bSMiklos Szeredi } 11563be5a52bSMiklos Szeredi 11573be5a52bSMiklos Szeredi /* 11586f9f1180SMiklos Szeredi * Set attributes, and at the same time refresh them. 11596f9f1180SMiklos Szeredi * 11606f9f1180SMiklos Szeredi * Truncation is slightly complicated, because the 'truncate' request 11616f9f1180SMiklos Szeredi * may fail, in which case we don't want to touch the mapping. 11629ffbb916SMiklos Szeredi * vmtruncate() doesn't allow for this case, so do the rlimit checking 11639ffbb916SMiklos Szeredi * and the actual truncation by hand. 11646f9f1180SMiklos Szeredi */ 116549d4914fSMiklos Szeredi static int fuse_do_setattr(struct dentry *entry, struct iattr *attr, 116649d4914fSMiklos Szeredi struct file *file) 11679e6268dbSMiklos Szeredi { 11689e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 11699e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 11709e6268dbSMiklos Szeredi struct fuse_req *req; 11719e6268dbSMiklos Szeredi struct fuse_setattr_in inarg; 11729e6268dbSMiklos Szeredi struct fuse_attr_out outarg; 11733be5a52bSMiklos Szeredi bool is_truncate = false; 11743be5a52bSMiklos Szeredi loff_t oldsize; 11759e6268dbSMiklos Szeredi int err; 11769e6268dbSMiklos Szeredi 1177e57ac683SMiklos Szeredi if (!fuse_allow_task(fc, current)) 1178e57ac683SMiklos Szeredi return -EACCES; 1179e57ac683SMiklos Szeredi 11801e9a4ed9SMiklos Szeredi if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 11811e9a4ed9SMiklos Szeredi err = inode_change_ok(inode, attr); 11821e9a4ed9SMiklos Szeredi if (err) 11831e9a4ed9SMiklos Szeredi return err; 11841e9a4ed9SMiklos Szeredi } 11851e9a4ed9SMiklos Szeredi 11866ff958edSMiklos Szeredi if ((attr->ia_valid & ATTR_OPEN) && fc->atomic_o_trunc) 11876ff958edSMiklos Szeredi return 0; 11886ff958edSMiklos Szeredi 11899e6268dbSMiklos Szeredi if (attr->ia_valid & ATTR_SIZE) { 11909e6268dbSMiklos Szeredi unsigned long limit; 1191b2d2272fSMiklos Szeredi if (IS_SWAPFILE(inode)) 1192b2d2272fSMiklos Szeredi return -ETXTBSY; 11939e6268dbSMiklos Szeredi limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; 11949e6268dbSMiklos Szeredi if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) { 11959e6268dbSMiklos Szeredi send_sig(SIGXFSZ, current, 0); 11969e6268dbSMiklos Szeredi return -EFBIG; 11979e6268dbSMiklos Szeredi } 11983be5a52bSMiklos Szeredi is_truncate = true; 11999e6268dbSMiklos Szeredi } 12009e6268dbSMiklos Szeredi 1201ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1202ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1203ce1d5a49SMiklos Szeredi return PTR_ERR(req); 12049e6268dbSMiklos Szeredi 12053be5a52bSMiklos Szeredi if (is_truncate) 12063be5a52bSMiklos Szeredi fuse_set_nowrite(inode); 12073be5a52bSMiklos Szeredi 12089e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 12090e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 1210befc649cSMiklos Szeredi iattr_to_fattr(attr, &inarg); 121149d4914fSMiklos Szeredi if (file) { 121249d4914fSMiklos Szeredi struct fuse_file *ff = file->private_data; 121349d4914fSMiklos Szeredi inarg.valid |= FATTR_FH; 121449d4914fSMiklos Szeredi inarg.fh = ff->fh; 121549d4914fSMiklos Szeredi } 1216f3332114SMiklos Szeredi if (attr->ia_valid & ATTR_SIZE) { 1217f3332114SMiklos Szeredi /* For mandatory locking in truncate */ 1218f3332114SMiklos Szeredi inarg.valid |= FATTR_LOCKOWNER; 1219f3332114SMiklos Szeredi inarg.lock_owner = fuse_lock_owner_id(fc, current->files); 1220f3332114SMiklos Szeredi } 12219e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_SETATTR; 12229e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 12239e6268dbSMiklos Szeredi req->in.numargs = 1; 12249e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 12259e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 12269e6268dbSMiklos Szeredi req->out.numargs = 1; 12270e9663eeSMiklos Szeredi if (fc->minor < 9) 12280e9663eeSMiklos Szeredi req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; 12290e9663eeSMiklos Szeredi else 12309e6268dbSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 12319e6268dbSMiklos Szeredi req->out.args[0].value = &outarg; 12329e6268dbSMiklos Szeredi request_send(fc, req); 12339e6268dbSMiklos Szeredi err = req->out.h.error; 12349e6268dbSMiklos Szeredi fuse_put_request(fc, req); 1235e00d2c2dSMiklos Szeredi if (err) { 1236e00d2c2dSMiklos Szeredi if (err == -EINTR) 1237e00d2c2dSMiklos Szeredi fuse_invalidate_attr(inode); 12383be5a52bSMiklos Szeredi goto error; 1239e00d2c2dSMiklos Szeredi } 1240e00d2c2dSMiklos Szeredi 12419e6268dbSMiklos Szeredi if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { 12429e6268dbSMiklos Szeredi make_bad_inode(inode); 12433be5a52bSMiklos Szeredi err = -EIO; 12443be5a52bSMiklos Szeredi goto error; 12459e6268dbSMiklos Szeredi } 12469e6268dbSMiklos Szeredi 12473be5a52bSMiklos Szeredi spin_lock(&fc->lock); 12483be5a52bSMiklos Szeredi fuse_change_attributes_common(inode, &outarg.attr, 12493be5a52bSMiklos Szeredi attr_timeout(&outarg)); 12503be5a52bSMiklos Szeredi oldsize = inode->i_size; 12513be5a52bSMiklos Szeredi i_size_write(inode, outarg.attr.size); 12523be5a52bSMiklos Szeredi 12533be5a52bSMiklos Szeredi if (is_truncate) { 12543be5a52bSMiklos Szeredi /* NOTE: this may release/reacquire fc->lock */ 12553be5a52bSMiklos Szeredi __fuse_release_nowrite(inode); 12563be5a52bSMiklos Szeredi } 12573be5a52bSMiklos Szeredi spin_unlock(&fc->lock); 12583be5a52bSMiklos Szeredi 12593be5a52bSMiklos Szeredi /* 12603be5a52bSMiklos Szeredi * Only call invalidate_inode_pages2() after removing 12613be5a52bSMiklos Szeredi * FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock. 12623be5a52bSMiklos Szeredi */ 12633be5a52bSMiklos Szeredi if (S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) { 12643be5a52bSMiklos Szeredi if (outarg.attr.size < oldsize) 12653be5a52bSMiklos Szeredi fuse_truncate(inode->i_mapping, outarg.attr.size); 12663be5a52bSMiklos Szeredi invalidate_inode_pages2(inode->i_mapping); 12673be5a52bSMiklos Szeredi } 12683be5a52bSMiklos Szeredi 1269e00d2c2dSMiklos Szeredi return 0; 12703be5a52bSMiklos Szeredi 12713be5a52bSMiklos Szeredi error: 12723be5a52bSMiklos Szeredi if (is_truncate) 12733be5a52bSMiklos Szeredi fuse_release_nowrite(inode); 12743be5a52bSMiklos Szeredi 12753be5a52bSMiklos Szeredi return err; 12769e6268dbSMiklos Szeredi } 12779e6268dbSMiklos Szeredi 127849d4914fSMiklos Szeredi static int fuse_setattr(struct dentry *entry, struct iattr *attr) 127949d4914fSMiklos Szeredi { 128049d4914fSMiklos Szeredi if (attr->ia_valid & ATTR_FILE) 128149d4914fSMiklos Szeredi return fuse_do_setattr(entry, attr, attr->ia_file); 128249d4914fSMiklos Szeredi else 128349d4914fSMiklos Szeredi return fuse_do_setattr(entry, attr, NULL); 128449d4914fSMiklos Szeredi } 128549d4914fSMiklos Szeredi 1286e5e5558eSMiklos Szeredi static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, 1287e5e5558eSMiklos Szeredi struct kstat *stat) 1288e5e5558eSMiklos Szeredi { 1289e5e5558eSMiklos Szeredi struct inode *inode = entry->d_inode; 1290244f6385SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1291244f6385SMiklos Szeredi 1292244f6385SMiklos Szeredi if (!fuse_allow_task(fc, current)) 1293244f6385SMiklos Szeredi return -EACCES; 1294244f6385SMiklos Szeredi 1295bcb4be80SMiklos Szeredi return fuse_update_attributes(inode, stat, NULL, NULL); 1296e5e5558eSMiklos Szeredi } 1297e5e5558eSMiklos Szeredi 129892a8780eSMiklos Szeredi static int fuse_setxattr(struct dentry *entry, const char *name, 129992a8780eSMiklos Szeredi const void *value, size_t size, int flags) 130092a8780eSMiklos Szeredi { 130192a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 130292a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 130392a8780eSMiklos Szeredi struct fuse_req *req; 130492a8780eSMiklos Szeredi struct fuse_setxattr_in inarg; 130592a8780eSMiklos Szeredi int err; 130692a8780eSMiklos Szeredi 130792a8780eSMiklos Szeredi if (fc->no_setxattr) 130892a8780eSMiklos Szeredi return -EOPNOTSUPP; 130992a8780eSMiklos Szeredi 1310ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1311ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1312ce1d5a49SMiklos Szeredi return PTR_ERR(req); 131392a8780eSMiklos Szeredi 131492a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 131592a8780eSMiklos Szeredi inarg.size = size; 131692a8780eSMiklos Szeredi inarg.flags = flags; 131792a8780eSMiklos Szeredi req->in.h.opcode = FUSE_SETXATTR; 131892a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 131992a8780eSMiklos Szeredi req->in.numargs = 3; 132092a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 132192a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 132292a8780eSMiklos Szeredi req->in.args[1].size = strlen(name) + 1; 132392a8780eSMiklos Szeredi req->in.args[1].value = name; 132492a8780eSMiklos Szeredi req->in.args[2].size = size; 132592a8780eSMiklos Szeredi req->in.args[2].value = value; 132692a8780eSMiklos Szeredi request_send(fc, req); 132792a8780eSMiklos Szeredi err = req->out.h.error; 132892a8780eSMiklos Szeredi fuse_put_request(fc, req); 132992a8780eSMiklos Szeredi if (err == -ENOSYS) { 133092a8780eSMiklos Szeredi fc->no_setxattr = 1; 133192a8780eSMiklos Szeredi err = -EOPNOTSUPP; 133292a8780eSMiklos Szeredi } 133392a8780eSMiklos Szeredi return err; 133492a8780eSMiklos Szeredi } 133592a8780eSMiklos Szeredi 133692a8780eSMiklos Szeredi static ssize_t fuse_getxattr(struct dentry *entry, const char *name, 133792a8780eSMiklos Szeredi void *value, size_t size) 133892a8780eSMiklos Szeredi { 133992a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 134092a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 134192a8780eSMiklos Szeredi struct fuse_req *req; 134292a8780eSMiklos Szeredi struct fuse_getxattr_in inarg; 134392a8780eSMiklos Szeredi struct fuse_getxattr_out outarg; 134492a8780eSMiklos Szeredi ssize_t ret; 134592a8780eSMiklos Szeredi 134692a8780eSMiklos Szeredi if (fc->no_getxattr) 134792a8780eSMiklos Szeredi return -EOPNOTSUPP; 134892a8780eSMiklos Szeredi 1349ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1350ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1351ce1d5a49SMiklos Szeredi return PTR_ERR(req); 135292a8780eSMiklos Szeredi 135392a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 135492a8780eSMiklos Szeredi inarg.size = size; 135592a8780eSMiklos Szeredi req->in.h.opcode = FUSE_GETXATTR; 135692a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 135792a8780eSMiklos Szeredi req->in.numargs = 2; 135892a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 135992a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 136092a8780eSMiklos Szeredi req->in.args[1].size = strlen(name) + 1; 136192a8780eSMiklos Szeredi req->in.args[1].value = name; 136292a8780eSMiklos Szeredi /* This is really two different operations rolled into one */ 136392a8780eSMiklos Szeredi req->out.numargs = 1; 136492a8780eSMiklos Szeredi if (size) { 136592a8780eSMiklos Szeredi req->out.argvar = 1; 136692a8780eSMiklos Szeredi req->out.args[0].size = size; 136792a8780eSMiklos Szeredi req->out.args[0].value = value; 136892a8780eSMiklos Szeredi } else { 136992a8780eSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 137092a8780eSMiklos Szeredi req->out.args[0].value = &outarg; 137192a8780eSMiklos Szeredi } 137292a8780eSMiklos Szeredi request_send(fc, req); 137392a8780eSMiklos Szeredi ret = req->out.h.error; 137492a8780eSMiklos Szeredi if (!ret) 137592a8780eSMiklos Szeredi ret = size ? req->out.args[0].size : outarg.size; 137692a8780eSMiklos Szeredi else { 137792a8780eSMiklos Szeredi if (ret == -ENOSYS) { 137892a8780eSMiklos Szeredi fc->no_getxattr = 1; 137992a8780eSMiklos Szeredi ret = -EOPNOTSUPP; 138092a8780eSMiklos Szeredi } 138192a8780eSMiklos Szeredi } 138292a8780eSMiklos Szeredi fuse_put_request(fc, req); 138392a8780eSMiklos Szeredi return ret; 138492a8780eSMiklos Szeredi } 138592a8780eSMiklos Szeredi 138692a8780eSMiklos Szeredi static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) 138792a8780eSMiklos Szeredi { 138892a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 138992a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 139092a8780eSMiklos Szeredi struct fuse_req *req; 139192a8780eSMiklos Szeredi struct fuse_getxattr_in inarg; 139292a8780eSMiklos Szeredi struct fuse_getxattr_out outarg; 139392a8780eSMiklos Szeredi ssize_t ret; 139492a8780eSMiklos Szeredi 1395e57ac683SMiklos Szeredi if (!fuse_allow_task(fc, current)) 1396e57ac683SMiklos Szeredi return -EACCES; 1397e57ac683SMiklos Szeredi 139892a8780eSMiklos Szeredi if (fc->no_listxattr) 139992a8780eSMiklos Szeredi return -EOPNOTSUPP; 140092a8780eSMiklos Szeredi 1401ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1402ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1403ce1d5a49SMiklos Szeredi return PTR_ERR(req); 140492a8780eSMiklos Szeredi 140592a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 140692a8780eSMiklos Szeredi inarg.size = size; 140792a8780eSMiklos Szeredi req->in.h.opcode = FUSE_LISTXATTR; 140892a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 140992a8780eSMiklos Szeredi req->in.numargs = 1; 141092a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 141192a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 141292a8780eSMiklos Szeredi /* This is really two different operations rolled into one */ 141392a8780eSMiklos Szeredi req->out.numargs = 1; 141492a8780eSMiklos Szeredi if (size) { 141592a8780eSMiklos Szeredi req->out.argvar = 1; 141692a8780eSMiklos Szeredi req->out.args[0].size = size; 141792a8780eSMiklos Szeredi req->out.args[0].value = list; 141892a8780eSMiklos Szeredi } else { 141992a8780eSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 142092a8780eSMiklos Szeredi req->out.args[0].value = &outarg; 142192a8780eSMiklos Szeredi } 142292a8780eSMiklos Szeredi request_send(fc, req); 142392a8780eSMiklos Szeredi ret = req->out.h.error; 142492a8780eSMiklos Szeredi if (!ret) 142592a8780eSMiklos Szeredi ret = size ? req->out.args[0].size : outarg.size; 142692a8780eSMiklos Szeredi else { 142792a8780eSMiklos Szeredi if (ret == -ENOSYS) { 142892a8780eSMiklos Szeredi fc->no_listxattr = 1; 142992a8780eSMiklos Szeredi ret = -EOPNOTSUPP; 143092a8780eSMiklos Szeredi } 143192a8780eSMiklos Szeredi } 143292a8780eSMiklos Szeredi fuse_put_request(fc, req); 143392a8780eSMiklos Szeredi return ret; 143492a8780eSMiklos Szeredi } 143592a8780eSMiklos Szeredi 143692a8780eSMiklos Szeredi static int fuse_removexattr(struct dentry *entry, const char *name) 143792a8780eSMiklos Szeredi { 143892a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 143992a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 144092a8780eSMiklos Szeredi struct fuse_req *req; 144192a8780eSMiklos Szeredi int err; 144292a8780eSMiklos Szeredi 144392a8780eSMiklos Szeredi if (fc->no_removexattr) 144492a8780eSMiklos Szeredi return -EOPNOTSUPP; 144592a8780eSMiklos Szeredi 1446ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1447ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1448ce1d5a49SMiklos Szeredi return PTR_ERR(req); 144992a8780eSMiklos Szeredi 145092a8780eSMiklos Szeredi req->in.h.opcode = FUSE_REMOVEXATTR; 145192a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 145292a8780eSMiklos Szeredi req->in.numargs = 1; 145392a8780eSMiklos Szeredi req->in.args[0].size = strlen(name) + 1; 145492a8780eSMiklos Szeredi req->in.args[0].value = name; 145592a8780eSMiklos Szeredi request_send(fc, req); 145692a8780eSMiklos Szeredi err = req->out.h.error; 145792a8780eSMiklos Szeredi fuse_put_request(fc, req); 145892a8780eSMiklos Szeredi if (err == -ENOSYS) { 145992a8780eSMiklos Szeredi fc->no_removexattr = 1; 146092a8780eSMiklos Szeredi err = -EOPNOTSUPP; 146192a8780eSMiklos Szeredi } 146292a8780eSMiklos Szeredi return err; 146392a8780eSMiklos Szeredi } 146492a8780eSMiklos Szeredi 1465754661f1SArjan van de Ven static const struct inode_operations fuse_dir_inode_operations = { 1466e5e5558eSMiklos Szeredi .lookup = fuse_lookup, 14679e6268dbSMiklos Szeredi .mkdir = fuse_mkdir, 14689e6268dbSMiklos Szeredi .symlink = fuse_symlink, 14699e6268dbSMiklos Szeredi .unlink = fuse_unlink, 14709e6268dbSMiklos Szeredi .rmdir = fuse_rmdir, 14719e6268dbSMiklos Szeredi .rename = fuse_rename, 14729e6268dbSMiklos Szeredi .link = fuse_link, 14739e6268dbSMiklos Szeredi .setattr = fuse_setattr, 14749e6268dbSMiklos Szeredi .create = fuse_create, 14759e6268dbSMiklos Szeredi .mknod = fuse_mknod, 1476e5e5558eSMiklos Szeredi .permission = fuse_permission, 1477e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 147892a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 147992a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 148092a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 148192a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 1482e5e5558eSMiklos Szeredi }; 1483e5e5558eSMiklos Szeredi 14844b6f5d20SArjan van de Ven static const struct file_operations fuse_dir_operations = { 1485b6aeadedSMiklos Szeredi .llseek = generic_file_llseek, 1486e5e5558eSMiklos Szeredi .read = generic_read_dir, 1487e5e5558eSMiklos Szeredi .readdir = fuse_readdir, 1488e5e5558eSMiklos Szeredi .open = fuse_dir_open, 1489e5e5558eSMiklos Szeredi .release = fuse_dir_release, 149082547981SMiklos Szeredi .fsync = fuse_dir_fsync, 1491e5e5558eSMiklos Szeredi }; 1492e5e5558eSMiklos Szeredi 1493754661f1SArjan van de Ven static const struct inode_operations fuse_common_inode_operations = { 14949e6268dbSMiklos Szeredi .setattr = fuse_setattr, 1495e5e5558eSMiklos Szeredi .permission = fuse_permission, 1496e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 149792a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 149892a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 149992a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 150092a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 1501e5e5558eSMiklos Szeredi }; 1502e5e5558eSMiklos Szeredi 1503754661f1SArjan van de Ven static const struct inode_operations fuse_symlink_inode_operations = { 15049e6268dbSMiklos Szeredi .setattr = fuse_setattr, 1505e5e5558eSMiklos Szeredi .follow_link = fuse_follow_link, 1506e5e5558eSMiklos Szeredi .put_link = fuse_put_link, 1507e5e5558eSMiklos Szeredi .readlink = generic_readlink, 1508e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 150992a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 151092a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 151192a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 151292a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 1513e5e5558eSMiklos Szeredi }; 1514e5e5558eSMiklos Szeredi 1515e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode) 1516e5e5558eSMiklos Szeredi { 1517e5e5558eSMiklos Szeredi inode->i_op = &fuse_common_inode_operations; 1518e5e5558eSMiklos Szeredi } 1519e5e5558eSMiklos Szeredi 1520e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode) 1521e5e5558eSMiklos Szeredi { 1522e5e5558eSMiklos Szeredi inode->i_op = &fuse_dir_inode_operations; 1523e5e5558eSMiklos Szeredi inode->i_fop = &fuse_dir_operations; 1524e5e5558eSMiklos Szeredi } 1525e5e5558eSMiklos Szeredi 1526e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode) 1527e5e5558eSMiklos Szeredi { 1528e5e5558eSMiklos Szeredi inode->i_op = &fuse_symlink_inode_operations; 1529e5e5558eSMiklos Szeredi } 1530