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 */ 660aa7c699SMiklos Szeredi static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o) 670aa7c699SMiklos Szeredi { 680a0898cfSMiklos Szeredi fuse_dentry_settime(entry, 690a0898cfSMiklos Szeredi time_to_jiffies(o->entry_valid, o->entry_valid_nsec)); 708cbdf1e6SMiklos Szeredi if (entry->d_inode) 718cbdf1e6SMiklos Szeredi get_fuse_inode(entry->d_inode)->i_time = 728cbdf1e6SMiklos Szeredi time_to_jiffies(o->attr_valid, o->attr_valid_nsec); 738cbdf1e6SMiklos Szeredi } 748cbdf1e6SMiklos Szeredi 756f9f1180SMiklos Szeredi /* 766f9f1180SMiklos Szeredi * Mark the attributes as stale, so that at the next call to 776f9f1180SMiklos Szeredi * ->getattr() they will be fetched from userspace 786f9f1180SMiklos Szeredi */ 798cbdf1e6SMiklos Szeredi void fuse_invalidate_attr(struct inode *inode) 808cbdf1e6SMiklos Szeredi { 810a0898cfSMiklos Szeredi get_fuse_inode(inode)->i_time = 0; 828cbdf1e6SMiklos Szeredi } 838cbdf1e6SMiklos Szeredi 846f9f1180SMiklos Szeredi /* 856f9f1180SMiklos Szeredi * Just mark the entry as stale, so that a next attempt to look it up 866f9f1180SMiklos Szeredi * will result in a new lookup call to userspace 876f9f1180SMiklos Szeredi * 886f9f1180SMiklos Szeredi * This is called when a dentry is about to become negative and the 896f9f1180SMiklos Szeredi * timeout is unknown (unlink, rmdir, rename and in some cases 906f9f1180SMiklos Szeredi * lookup) 916f9f1180SMiklos Szeredi */ 928cbdf1e6SMiklos Szeredi static void fuse_invalidate_entry_cache(struct dentry *entry) 938cbdf1e6SMiklos Szeredi { 940a0898cfSMiklos Szeredi fuse_dentry_settime(entry, 0); 958cbdf1e6SMiklos Szeredi } 968cbdf1e6SMiklos Szeredi 976f9f1180SMiklos Szeredi /* 986f9f1180SMiklos Szeredi * Same as fuse_invalidate_entry_cache(), but also try to remove the 996f9f1180SMiklos Szeredi * dentry from the hash 1006f9f1180SMiklos Szeredi */ 1018cbdf1e6SMiklos Szeredi static void fuse_invalidate_entry(struct dentry *entry) 1028cbdf1e6SMiklos Szeredi { 1038cbdf1e6SMiklos Szeredi d_invalidate(entry); 1048cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 1050aa7c699SMiklos Szeredi } 1060aa7c699SMiklos Szeredi 107e5e5558eSMiklos Szeredi static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, 108e5e5558eSMiklos Szeredi struct dentry *entry, 109e5e5558eSMiklos Szeredi struct fuse_entry_out *outarg) 110e5e5558eSMiklos Szeredi { 111e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_LOOKUP; 112e5e5558eSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 113e5e5558eSMiklos Szeredi req->in.numargs = 1; 114e5e5558eSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 115e5e5558eSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 116e5e5558eSMiklos Szeredi req->out.numargs = 1; 117e5e5558eSMiklos Szeredi req->out.args[0].size = sizeof(struct fuse_entry_out); 118e5e5558eSMiklos Szeredi req->out.args[0].value = outarg; 119e5e5558eSMiklos Szeredi } 120e5e5558eSMiklos Szeredi 1216f9f1180SMiklos Szeredi /* 1226f9f1180SMiklos Szeredi * Check whether the dentry is still valid 1236f9f1180SMiklos Szeredi * 1246f9f1180SMiklos Szeredi * If the entry validity timeout has expired and the dentry is 1256f9f1180SMiklos Szeredi * positive, try to redo the lookup. If the lookup results in a 1266f9f1180SMiklos Szeredi * different inode, then let the VFS invalidate the dentry and redo 1276f9f1180SMiklos Szeredi * the lookup once more. If the lookup results in the same inode, 1286f9f1180SMiklos Szeredi * then refresh the attributes, timeouts and mark the dentry valid. 1296f9f1180SMiklos Szeredi */ 130e5e5558eSMiklos Szeredi static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) 131e5e5558eSMiklos Szeredi { 1328cbdf1e6SMiklos Szeredi struct inode *inode = entry->d_inode; 1338cbdf1e6SMiklos Szeredi 1348cbdf1e6SMiklos Szeredi if (inode && is_bad_inode(inode)) 135e5e5558eSMiklos Szeredi return 0; 1360a0898cfSMiklos Szeredi else if (fuse_dentry_time(entry) < get_jiffies_64()) { 137e5e5558eSMiklos Szeredi int err; 138e5e5558eSMiklos Szeredi struct fuse_entry_out outarg; 1398cbdf1e6SMiklos Szeredi struct fuse_conn *fc; 1408cbdf1e6SMiklos Szeredi struct fuse_req *req; 1418cbdf1e6SMiklos Szeredi 1426f9f1180SMiklos Szeredi /* Doesn't hurt to "reset" the validity timeout */ 1438cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 14450322fe7SMiklos Szeredi 14550322fe7SMiklos Szeredi /* For negative dentries, always do a fresh lookup */ 1468cbdf1e6SMiklos Szeredi if (!inode) 1478cbdf1e6SMiklos Szeredi return 0; 1488cbdf1e6SMiklos Szeredi 1498cbdf1e6SMiklos Szeredi fc = get_fuse_conn(inode); 150ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 151ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 152e5e5558eSMiklos Szeredi return 0; 153e5e5558eSMiklos Szeredi 154e5e5558eSMiklos Szeredi fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg); 1557c352bdfSMiklos Szeredi request_send(fc, req); 156e5e5558eSMiklos Szeredi err = req->out.h.error; 15750322fe7SMiklos Szeredi /* Zero nodeid is same as -ENOENT */ 15850322fe7SMiklos Szeredi if (!err && !outarg.nodeid) 15950322fe7SMiklos Szeredi err = -ENOENT; 1609e6268dbSMiklos Szeredi if (!err) { 1618cbdf1e6SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 1629e6268dbSMiklos Szeredi if (outarg.nodeid != get_node_id(inode)) { 1639e6268dbSMiklos Szeredi fuse_send_forget(fc, req, outarg.nodeid, 1); 1649e6268dbSMiklos Szeredi return 0; 1659e6268dbSMiklos Szeredi } 1668da5ff23SMiklos Szeredi spin_lock(&fc->lock); 1679e6268dbSMiklos Szeredi fi->nlookup ++; 1688da5ff23SMiklos Szeredi spin_unlock(&fc->lock); 1699e6268dbSMiklos Szeredi } 170e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 1719e6268dbSMiklos Szeredi if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) 172e5e5558eSMiklos Szeredi return 0; 173e5e5558eSMiklos Szeredi 174e5e5558eSMiklos Szeredi fuse_change_attributes(inode, &outarg.attr); 1750aa7c699SMiklos Szeredi fuse_change_timeout(entry, &outarg); 176e5e5558eSMiklos Szeredi } 177e5e5558eSMiklos Szeredi return 1; 178e5e5558eSMiklos Szeredi } 179e5e5558eSMiklos Szeredi 1808bfc016dSMiklos Szeredi static int invalid_nodeid(u64 nodeid) 1812827d0b2SMiklos Szeredi { 1822827d0b2SMiklos Szeredi return !nodeid || nodeid == FUSE_ROOT_ID; 1832827d0b2SMiklos Szeredi } 1842827d0b2SMiklos Szeredi 185e5e5558eSMiklos Szeredi static struct dentry_operations fuse_dentry_operations = { 186e5e5558eSMiklos Szeredi .d_revalidate = fuse_dentry_revalidate, 187e5e5558eSMiklos Szeredi }; 188e5e5558eSMiklos Szeredi 1898bfc016dSMiklos Szeredi static int valid_mode(int m) 19039ee059aSMiklos Szeredi { 19139ee059aSMiklos Szeredi return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) || 19239ee059aSMiklos Szeredi S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); 19339ee059aSMiklos Szeredi } 19439ee059aSMiklos Szeredi 195*d2a85164SMiklos Szeredi /* 196*d2a85164SMiklos Szeredi * Add a directory inode to a dentry, ensuring that no other dentry 197*d2a85164SMiklos Szeredi * refers to this inode. Called with fc->inst_mutex. 198*d2a85164SMiklos Szeredi */ 199*d2a85164SMiklos Szeredi static int fuse_d_add_directory(struct dentry *entry, struct inode *inode) 200*d2a85164SMiklos Szeredi { 201*d2a85164SMiklos Szeredi struct dentry *alias = d_find_alias(inode); 202*d2a85164SMiklos Szeredi if (alias) { 203*d2a85164SMiklos Szeredi /* This tries to shrink the subtree below alias */ 204*d2a85164SMiklos Szeredi fuse_invalidate_entry(alias); 205*d2a85164SMiklos Szeredi dput(alias); 206*d2a85164SMiklos Szeredi if (!list_empty(&inode->i_dentry)) 207*d2a85164SMiklos Szeredi return -EBUSY; 208*d2a85164SMiklos Szeredi } 209*d2a85164SMiklos Szeredi d_add(entry, inode); 210*d2a85164SMiklos Szeredi return 0; 211*d2a85164SMiklos Szeredi } 212*d2a85164SMiklos Szeredi 2130aa7c699SMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, 2140aa7c699SMiklos Szeredi struct nameidata *nd) 215e5e5558eSMiklos Szeredi { 216e5e5558eSMiklos Szeredi int err; 217e5e5558eSMiklos Szeredi struct fuse_entry_out outarg; 218e5e5558eSMiklos Szeredi struct inode *inode = NULL; 219e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 220e5e5558eSMiklos Szeredi struct fuse_req *req; 221e5e5558eSMiklos Szeredi 222e5e5558eSMiklos Szeredi if (entry->d_name.len > FUSE_NAME_MAX) 2230aa7c699SMiklos Szeredi return ERR_PTR(-ENAMETOOLONG); 224e5e5558eSMiklos Szeredi 225ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 226ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 227ce1d5a49SMiklos Szeredi return ERR_PTR(PTR_ERR(req)); 228e5e5558eSMiklos Szeredi 229e5e5558eSMiklos Szeredi fuse_lookup_init(req, dir, entry, &outarg); 230e5e5558eSMiklos Szeredi request_send(fc, req); 231e5e5558eSMiklos Szeredi err = req->out.h.error; 23250322fe7SMiklos Szeredi /* Zero nodeid is same as -ENOENT, but with valid timeout */ 23350322fe7SMiklos Szeredi if (!err && outarg.nodeid && 23450322fe7SMiklos Szeredi (invalid_nodeid(outarg.nodeid) || !valid_mode(outarg.attr.mode))) 235ee4e5271SMiklos Szeredi err = -EIO; 2368cbdf1e6SMiklos Szeredi if (!err && outarg.nodeid) { 237e5e5558eSMiklos Szeredi inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 2389e6268dbSMiklos Szeredi &outarg.attr); 239e5e5558eSMiklos Szeredi if (!inode) { 2409e6268dbSMiklos Szeredi fuse_send_forget(fc, req, outarg.nodeid, 1); 2410aa7c699SMiklos Szeredi return ERR_PTR(-ENOMEM); 242e5e5558eSMiklos Szeredi } 243e5e5558eSMiklos Szeredi } 244e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 245e5e5558eSMiklos Szeredi if (err && err != -ENOENT) 2460aa7c699SMiklos Szeredi return ERR_PTR(err); 247e5e5558eSMiklos Szeredi 248*d2a85164SMiklos Szeredi if (inode && S_ISDIR(inode->i_mode)) { 249*d2a85164SMiklos Szeredi mutex_lock(&fc->inst_mutex); 250*d2a85164SMiklos Szeredi err = fuse_d_add_directory(entry, inode); 251*d2a85164SMiklos Szeredi mutex_unlock(&fc->inst_mutex); 252*d2a85164SMiklos Szeredi if (err) { 2530aa7c699SMiklos Szeredi iput(inode); 254*d2a85164SMiklos Szeredi return ERR_PTR(err); 255e5e5558eSMiklos Szeredi } 256*d2a85164SMiklos Szeredi } else 2570aa7c699SMiklos Szeredi d_add(entry, inode); 258*d2a85164SMiklos Szeredi 259e5e5558eSMiklos Szeredi entry->d_op = &fuse_dentry_operations; 2608cbdf1e6SMiklos Szeredi if (!err) 2610aa7c699SMiklos Szeredi fuse_change_timeout(entry, &outarg); 2628cbdf1e6SMiklos Szeredi else 2638cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 2640aa7c699SMiklos Szeredi return NULL; 265e5e5558eSMiklos Szeredi } 266e5e5558eSMiklos Szeredi 2676f9f1180SMiklos Szeredi /* 26851eb01e7SMiklos Szeredi * Synchronous release for the case when something goes wrong in CREATE_OPEN 26951eb01e7SMiklos Szeredi */ 27051eb01e7SMiklos Szeredi static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff, 27151eb01e7SMiklos Szeredi u64 nodeid, int flags) 27251eb01e7SMiklos Szeredi { 27351eb01e7SMiklos Szeredi struct fuse_req *req; 27451eb01e7SMiklos Szeredi 27551eb01e7SMiklos Szeredi req = fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE); 27651eb01e7SMiklos Szeredi req->force = 1; 27751eb01e7SMiklos Szeredi request_send(fc, req); 27851eb01e7SMiklos Szeredi fuse_put_request(fc, req); 27951eb01e7SMiklos Szeredi } 28051eb01e7SMiklos Szeredi 28151eb01e7SMiklos Szeredi /* 2826f9f1180SMiklos Szeredi * Atomic create+open operation 2836f9f1180SMiklos Szeredi * 2846f9f1180SMiklos Szeredi * If the filesystem doesn't support this, then fall back to separate 2856f9f1180SMiklos Szeredi * 'mknod' + 'open' requests. 2866f9f1180SMiklos Szeredi */ 287fd72faacSMiklos Szeredi static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, 288fd72faacSMiklos Szeredi struct nameidata *nd) 289fd72faacSMiklos Szeredi { 290fd72faacSMiklos Szeredi int err; 291fd72faacSMiklos Szeredi struct inode *inode; 292fd72faacSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 293fd72faacSMiklos Szeredi struct fuse_req *req; 29451eb01e7SMiklos Szeredi struct fuse_req *forget_req; 295fd72faacSMiklos Szeredi struct fuse_open_in inarg; 296fd72faacSMiklos Szeredi struct fuse_open_out outopen; 297fd72faacSMiklos Szeredi struct fuse_entry_out outentry; 298fd72faacSMiklos Szeredi struct fuse_file *ff; 299fd72faacSMiklos Szeredi struct file *file; 300fd72faacSMiklos Szeredi int flags = nd->intent.open.flags - 1; 301fd72faacSMiklos Szeredi 302fd72faacSMiklos Szeredi if (fc->no_create) 303ce1d5a49SMiklos Szeredi return -ENOSYS; 304fd72faacSMiklos Szeredi 30551eb01e7SMiklos Szeredi forget_req = fuse_get_req(fc); 30651eb01e7SMiklos Szeredi if (IS_ERR(forget_req)) 30751eb01e7SMiklos Szeredi return PTR_ERR(forget_req); 30851eb01e7SMiklos Szeredi 309ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 31051eb01e7SMiklos Szeredi err = PTR_ERR(req); 311ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 31251eb01e7SMiklos Szeredi goto out_put_forget_req; 313fd72faacSMiklos Szeredi 314ce1d5a49SMiklos Szeredi err = -ENOMEM; 315fd72faacSMiklos Szeredi ff = fuse_file_alloc(); 316fd72faacSMiklos Szeredi if (!ff) 317fd72faacSMiklos Szeredi goto out_put_request; 318fd72faacSMiklos Szeredi 319fd72faacSMiklos Szeredi flags &= ~O_NOCTTY; 320fd72faacSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 321fd72faacSMiklos Szeredi inarg.flags = flags; 322fd72faacSMiklos Szeredi inarg.mode = mode; 323fd72faacSMiklos Szeredi req->in.h.opcode = FUSE_CREATE; 324fd72faacSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 325fd72faacSMiklos Szeredi req->in.numargs = 2; 326fd72faacSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 327fd72faacSMiklos Szeredi req->in.args[0].value = &inarg; 328fd72faacSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 329fd72faacSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 330fd72faacSMiklos Szeredi req->out.numargs = 2; 331fd72faacSMiklos Szeredi req->out.args[0].size = sizeof(outentry); 332fd72faacSMiklos Szeredi req->out.args[0].value = &outentry; 333fd72faacSMiklos Szeredi req->out.args[1].size = sizeof(outopen); 334fd72faacSMiklos Szeredi req->out.args[1].value = &outopen; 335fd72faacSMiklos Szeredi request_send(fc, req); 336fd72faacSMiklos Szeredi err = req->out.h.error; 337fd72faacSMiklos Szeredi if (err) { 338fd72faacSMiklos Szeredi if (err == -ENOSYS) 339fd72faacSMiklos Szeredi fc->no_create = 1; 340fd72faacSMiklos Szeredi goto out_free_ff; 341fd72faacSMiklos Szeredi } 342fd72faacSMiklos Szeredi 343fd72faacSMiklos Szeredi err = -EIO; 3442827d0b2SMiklos Szeredi if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid)) 345fd72faacSMiklos Szeredi goto out_free_ff; 346fd72faacSMiklos Szeredi 34751eb01e7SMiklos Szeredi fuse_put_request(fc, req); 348fd72faacSMiklos Szeredi inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, 349fd72faacSMiklos Szeredi &outentry.attr); 350fd72faacSMiklos Szeredi if (!inode) { 351fd72faacSMiklos Szeredi flags &= ~(O_CREAT | O_EXCL | O_TRUNC); 352fd72faacSMiklos Szeredi ff->fh = outopen.fh; 35351eb01e7SMiklos Szeredi fuse_sync_release(fc, ff, outentry.nodeid, flags); 35451eb01e7SMiklos Szeredi fuse_send_forget(fc, forget_req, outentry.nodeid, 1); 35551eb01e7SMiklos Szeredi return -ENOMEM; 356fd72faacSMiklos Szeredi } 35751eb01e7SMiklos Szeredi fuse_put_request(fc, forget_req); 358fd72faacSMiklos Szeredi d_instantiate(entry, inode); 3590aa7c699SMiklos Szeredi fuse_change_timeout(entry, &outentry); 360fd72faacSMiklos Szeredi file = lookup_instantiate_filp(nd, entry, generic_file_open); 361fd72faacSMiklos Szeredi if (IS_ERR(file)) { 362fd72faacSMiklos Szeredi ff->fh = outopen.fh; 36351eb01e7SMiklos Szeredi fuse_sync_release(fc, ff, outentry.nodeid, flags); 364fd72faacSMiklos Szeredi return PTR_ERR(file); 365fd72faacSMiklos Szeredi } 366fd72faacSMiklos Szeredi fuse_finish_open(inode, file, ff, &outopen); 367fd72faacSMiklos Szeredi return 0; 368fd72faacSMiklos Szeredi 369fd72faacSMiklos Szeredi out_free_ff: 370fd72faacSMiklos Szeredi fuse_file_free(ff); 371fd72faacSMiklos Szeredi out_put_request: 372fd72faacSMiklos Szeredi fuse_put_request(fc, req); 37351eb01e7SMiklos Szeredi out_put_forget_req: 37451eb01e7SMiklos Szeredi fuse_put_request(fc, forget_req); 375fd72faacSMiklos Szeredi return err; 376fd72faacSMiklos Szeredi } 377fd72faacSMiklos Szeredi 3786f9f1180SMiklos Szeredi /* 3796f9f1180SMiklos Szeredi * Code shared between mknod, mkdir, symlink and link 3806f9f1180SMiklos Szeredi */ 3819e6268dbSMiklos Szeredi static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, 3829e6268dbSMiklos Szeredi struct inode *dir, struct dentry *entry, 3839e6268dbSMiklos Szeredi int mode) 3849e6268dbSMiklos Szeredi { 3859e6268dbSMiklos Szeredi struct fuse_entry_out outarg; 3869e6268dbSMiklos Szeredi struct inode *inode; 3879e6268dbSMiklos Szeredi int err; 3889e6268dbSMiklos Szeredi 3899e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 3909e6268dbSMiklos Szeredi req->out.numargs = 1; 3919e6268dbSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 3929e6268dbSMiklos Szeredi req->out.args[0].value = &outarg; 3939e6268dbSMiklos Szeredi request_send(fc, req); 3949e6268dbSMiklos Szeredi err = req->out.h.error; 3959e6268dbSMiklos Szeredi if (err) { 3969e6268dbSMiklos Szeredi fuse_put_request(fc, req); 3979e6268dbSMiklos Szeredi return err; 3989e6268dbSMiklos Szeredi } 39939ee059aSMiklos Szeredi err = -EIO; 40039ee059aSMiklos Szeredi if (invalid_nodeid(outarg.nodeid)) 40139ee059aSMiklos Szeredi goto out_put_request; 40239ee059aSMiklos Szeredi 40339ee059aSMiklos Szeredi if ((outarg.attr.mode ^ mode) & S_IFMT) 40439ee059aSMiklos Szeredi goto out_put_request; 40539ee059aSMiklos Szeredi 4069e6268dbSMiklos Szeredi inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 4079e6268dbSMiklos Szeredi &outarg.attr); 4089e6268dbSMiklos Szeredi if (!inode) { 4099e6268dbSMiklos Szeredi fuse_send_forget(fc, req, outarg.nodeid, 1); 4109e6268dbSMiklos Szeredi return -ENOMEM; 4119e6268dbSMiklos Szeredi } 4129e6268dbSMiklos Szeredi fuse_put_request(fc, req); 4139e6268dbSMiklos Szeredi 414*d2a85164SMiklos Szeredi if (S_ISDIR(inode->i_mode)) { 415*d2a85164SMiklos Szeredi struct dentry *alias; 416*d2a85164SMiklos Szeredi mutex_lock(&fc->inst_mutex); 417*d2a85164SMiklos Szeredi alias = d_find_alias(inode); 418*d2a85164SMiklos Szeredi if (alias) { 419*d2a85164SMiklos Szeredi /* New directory must have moved since mkdir */ 420*d2a85164SMiklos Szeredi mutex_unlock(&fc->inst_mutex); 421*d2a85164SMiklos Szeredi dput(alias); 4229e6268dbSMiklos Szeredi iput(inode); 423*d2a85164SMiklos Szeredi return -EBUSY; 4249e6268dbSMiklos Szeredi } 4259e6268dbSMiklos Szeredi d_instantiate(entry, inode); 426*d2a85164SMiklos Szeredi mutex_unlock(&fc->inst_mutex); 427*d2a85164SMiklos Szeredi } else 428*d2a85164SMiklos Szeredi d_instantiate(entry, inode); 429*d2a85164SMiklos Szeredi 4300aa7c699SMiklos Szeredi fuse_change_timeout(entry, &outarg); 4319e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 4329e6268dbSMiklos Szeredi return 0; 43339ee059aSMiklos Szeredi 43439ee059aSMiklos Szeredi out_put_request: 43539ee059aSMiklos Szeredi fuse_put_request(fc, req); 43639ee059aSMiklos Szeredi return err; 4379e6268dbSMiklos Szeredi } 4389e6268dbSMiklos Szeredi 4399e6268dbSMiklos Szeredi static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, 4409e6268dbSMiklos Szeredi dev_t rdev) 4419e6268dbSMiklos Szeredi { 4429e6268dbSMiklos Szeredi struct fuse_mknod_in inarg; 4439e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 444ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 445ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 446ce1d5a49SMiklos Szeredi return PTR_ERR(req); 4479e6268dbSMiklos Szeredi 4489e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 4499e6268dbSMiklos Szeredi inarg.mode = mode; 4509e6268dbSMiklos Szeredi inarg.rdev = new_encode_dev(rdev); 4519e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_MKNOD; 4529e6268dbSMiklos Szeredi req->in.numargs = 2; 4539e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 4549e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 4559e6268dbSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 4569e6268dbSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 4579e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, mode); 4589e6268dbSMiklos Szeredi } 4599e6268dbSMiklos Szeredi 4609e6268dbSMiklos Szeredi static int fuse_create(struct inode *dir, struct dentry *entry, int mode, 4619e6268dbSMiklos Szeredi struct nameidata *nd) 4629e6268dbSMiklos Szeredi { 463fd72faacSMiklos Szeredi if (nd && (nd->flags & LOOKUP_CREATE)) { 464fd72faacSMiklos Szeredi int err = fuse_create_open(dir, entry, mode, nd); 465fd72faacSMiklos Szeredi if (err != -ENOSYS) 466fd72faacSMiklos Szeredi return err; 467fd72faacSMiklos Szeredi /* Fall back on mknod */ 468fd72faacSMiklos Szeredi } 4699e6268dbSMiklos Szeredi return fuse_mknod(dir, entry, mode, 0); 4709e6268dbSMiklos Szeredi } 4719e6268dbSMiklos Szeredi 4729e6268dbSMiklos Szeredi static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode) 4739e6268dbSMiklos Szeredi { 4749e6268dbSMiklos Szeredi struct fuse_mkdir_in inarg; 4759e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 476ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 477ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 478ce1d5a49SMiklos Szeredi return PTR_ERR(req); 4799e6268dbSMiklos Szeredi 4809e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 4819e6268dbSMiklos Szeredi inarg.mode = mode; 4829e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_MKDIR; 4839e6268dbSMiklos Szeredi req->in.numargs = 2; 4849e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 4859e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 4869e6268dbSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 4879e6268dbSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 4889e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, S_IFDIR); 4899e6268dbSMiklos Szeredi } 4909e6268dbSMiklos Szeredi 4919e6268dbSMiklos Szeredi static int fuse_symlink(struct inode *dir, struct dentry *entry, 4929e6268dbSMiklos Szeredi const char *link) 4939e6268dbSMiklos Szeredi { 4949e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 4959e6268dbSMiklos Szeredi unsigned len = strlen(link) + 1; 496ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 497ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 498ce1d5a49SMiklos Szeredi return PTR_ERR(req); 4999e6268dbSMiklos Szeredi 5009e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_SYMLINK; 5019e6268dbSMiklos Szeredi req->in.numargs = 2; 5029e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 5039e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 5049e6268dbSMiklos Szeredi req->in.args[1].size = len; 5059e6268dbSMiklos Szeredi req->in.args[1].value = link; 5069e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, S_IFLNK); 5079e6268dbSMiklos Szeredi } 5089e6268dbSMiklos Szeredi 5099e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry) 5109e6268dbSMiklos Szeredi { 5119e6268dbSMiklos Szeredi int err; 5129e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 513ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 514ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 515ce1d5a49SMiklos Szeredi return PTR_ERR(req); 5169e6268dbSMiklos Szeredi 5179e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_UNLINK; 5189e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 5199e6268dbSMiklos Szeredi req->in.numargs = 1; 5209e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 5219e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 5229e6268dbSMiklos Szeredi request_send(fc, req); 5239e6268dbSMiklos Szeredi err = req->out.h.error; 5249e6268dbSMiklos Szeredi fuse_put_request(fc, req); 5259e6268dbSMiklos Szeredi if (!err) { 5269e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 5279e6268dbSMiklos Szeredi 5289e6268dbSMiklos Szeredi /* Set nlink to zero so the inode can be cleared, if 5299e6268dbSMiklos Szeredi the inode does have more links this will be 5309e6268dbSMiklos Szeredi discovered at the next lookup/getattr */ 531ce71ec36SDave Hansen clear_nlink(inode); 5329e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 5339e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 5348cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 5359e6268dbSMiklos Szeredi } else if (err == -EINTR) 5369e6268dbSMiklos Szeredi fuse_invalidate_entry(entry); 5379e6268dbSMiklos Szeredi return err; 5389e6268dbSMiklos Szeredi } 5399e6268dbSMiklos Szeredi 5409e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry) 5419e6268dbSMiklos Szeredi { 5429e6268dbSMiklos Szeredi int err; 5439e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 544ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 545ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 546ce1d5a49SMiklos Szeredi return PTR_ERR(req); 5479e6268dbSMiklos Szeredi 5489e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_RMDIR; 5499e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 5509e6268dbSMiklos Szeredi req->in.numargs = 1; 5519e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 5529e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 5539e6268dbSMiklos Szeredi request_send(fc, req); 5549e6268dbSMiklos Szeredi err = req->out.h.error; 5559e6268dbSMiklos Szeredi fuse_put_request(fc, req); 5569e6268dbSMiklos Szeredi if (!err) { 557ce71ec36SDave Hansen clear_nlink(entry->d_inode); 5589e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 5598cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 5609e6268dbSMiklos Szeredi } else if (err == -EINTR) 5619e6268dbSMiklos Szeredi fuse_invalidate_entry(entry); 5629e6268dbSMiklos Szeredi return err; 5639e6268dbSMiklos Szeredi } 5649e6268dbSMiklos Szeredi 5659e6268dbSMiklos Szeredi static int fuse_rename(struct inode *olddir, struct dentry *oldent, 5669e6268dbSMiklos Szeredi struct inode *newdir, struct dentry *newent) 5679e6268dbSMiklos Szeredi { 5689e6268dbSMiklos Szeredi int err; 5699e6268dbSMiklos Szeredi struct fuse_rename_in inarg; 5709e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(olddir); 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 memset(&inarg, 0, sizeof(inarg)); 5769e6268dbSMiklos Szeredi inarg.newdir = get_node_id(newdir); 5779e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_RENAME; 5789e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(olddir); 5799e6268dbSMiklos Szeredi req->in.numargs = 3; 5809e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 5819e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 5829e6268dbSMiklos Szeredi req->in.args[1].size = oldent->d_name.len + 1; 5839e6268dbSMiklos Szeredi req->in.args[1].value = oldent->d_name.name; 5849e6268dbSMiklos Szeredi req->in.args[2].size = newent->d_name.len + 1; 5859e6268dbSMiklos Szeredi req->in.args[2].value = newent->d_name.name; 5869e6268dbSMiklos Szeredi request_send(fc, req); 5879e6268dbSMiklos Szeredi err = req->out.h.error; 5889e6268dbSMiklos Szeredi fuse_put_request(fc, req); 5899e6268dbSMiklos Szeredi if (!err) { 5909e6268dbSMiklos Szeredi fuse_invalidate_attr(olddir); 5919e6268dbSMiklos Szeredi if (olddir != newdir) 5929e6268dbSMiklos Szeredi fuse_invalidate_attr(newdir); 5938cbdf1e6SMiklos Szeredi 5948cbdf1e6SMiklos Szeredi /* newent will end up negative */ 5958cbdf1e6SMiklos Szeredi if (newent->d_inode) 5968cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(newent); 5979e6268dbSMiklos Szeredi } else if (err == -EINTR) { 5989e6268dbSMiklos Szeredi /* If request was interrupted, DEITY only knows if the 5999e6268dbSMiklos Szeredi rename actually took place. If the invalidation 6009e6268dbSMiklos Szeredi fails (e.g. some process has CWD under the renamed 6019e6268dbSMiklos Szeredi directory), then there can be inconsistency between 6029e6268dbSMiklos Szeredi the dcache and the real filesystem. Tough luck. */ 6039e6268dbSMiklos Szeredi fuse_invalidate_entry(oldent); 6049e6268dbSMiklos Szeredi if (newent->d_inode) 6059e6268dbSMiklos Szeredi fuse_invalidate_entry(newent); 6069e6268dbSMiklos Szeredi } 6079e6268dbSMiklos Szeredi 6089e6268dbSMiklos Szeredi return err; 6099e6268dbSMiklos Szeredi } 6109e6268dbSMiklos Szeredi 6119e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir, 6129e6268dbSMiklos Szeredi struct dentry *newent) 6139e6268dbSMiklos Szeredi { 6149e6268dbSMiklos Szeredi int err; 6159e6268dbSMiklos Szeredi struct fuse_link_in inarg; 6169e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 6179e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 618ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 619ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 620ce1d5a49SMiklos Szeredi return PTR_ERR(req); 6219e6268dbSMiklos Szeredi 6229e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 6239e6268dbSMiklos Szeredi inarg.oldnodeid = get_node_id(inode); 6249e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_LINK; 6259e6268dbSMiklos Szeredi req->in.numargs = 2; 6269e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 6279e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 6289e6268dbSMiklos Szeredi req->in.args[1].size = newent->d_name.len + 1; 6299e6268dbSMiklos Szeredi req->in.args[1].value = newent->d_name.name; 6309e6268dbSMiklos Szeredi err = create_new_entry(fc, req, newdir, newent, inode->i_mode); 6319e6268dbSMiklos Szeredi /* Contrary to "normal" filesystems it can happen that link 6329e6268dbSMiklos Szeredi makes two "logical" inodes point to the same "physical" 6339e6268dbSMiklos Szeredi inode. We invalidate the attributes of the old one, so it 6349e6268dbSMiklos Szeredi will reflect changes in the backing inode (link count, 6359e6268dbSMiklos Szeredi etc.) 6369e6268dbSMiklos Szeredi */ 6379e6268dbSMiklos Szeredi if (!err || err == -EINTR) 6389e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 6399e6268dbSMiklos Szeredi return err; 6409e6268dbSMiklos Szeredi } 6419e6268dbSMiklos Szeredi 642e5e5558eSMiklos Szeredi int fuse_do_getattr(struct inode *inode) 643e5e5558eSMiklos Szeredi { 644e5e5558eSMiklos Szeredi int err; 645e5e5558eSMiklos Szeredi struct fuse_attr_out arg; 646e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 647ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 648ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 649ce1d5a49SMiklos Szeredi return PTR_ERR(req); 650e5e5558eSMiklos Szeredi 651e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_GETATTR; 652e5e5558eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 653e5e5558eSMiklos Szeredi req->out.numargs = 1; 654e5e5558eSMiklos Szeredi req->out.args[0].size = sizeof(arg); 655e5e5558eSMiklos Szeredi req->out.args[0].value = &arg; 656e5e5558eSMiklos Szeredi request_send(fc, req); 657e5e5558eSMiklos Szeredi err = req->out.h.error; 658e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 659e5e5558eSMiklos Szeredi if (!err) { 660e5e5558eSMiklos Szeredi if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) { 661e5e5558eSMiklos Szeredi make_bad_inode(inode); 662e5e5558eSMiklos Szeredi err = -EIO; 663e5e5558eSMiklos Szeredi } else { 664e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 665e5e5558eSMiklos Szeredi fuse_change_attributes(inode, &arg.attr); 666e5e5558eSMiklos Szeredi fi->i_time = time_to_jiffies(arg.attr_valid, 667e5e5558eSMiklos Szeredi arg.attr_valid_nsec); 668e5e5558eSMiklos Szeredi } 669e5e5558eSMiklos Szeredi } 670e5e5558eSMiklos Szeredi return err; 671e5e5558eSMiklos Szeredi } 672e5e5558eSMiklos Szeredi 67387729a55SMiklos Szeredi /* 67487729a55SMiklos Szeredi * Calling into a user-controlled filesystem gives the filesystem 67587729a55SMiklos Szeredi * daemon ptrace-like capabilities over the requester process. This 67687729a55SMiklos Szeredi * means, that the filesystem daemon is able to record the exact 67787729a55SMiklos Szeredi * filesystem operations performed, and can also control the behavior 67887729a55SMiklos Szeredi * of the requester process in otherwise impossible ways. For example 67987729a55SMiklos Szeredi * it can delay the operation for arbitrary length of time allowing 68087729a55SMiklos Szeredi * DoS against the requester. 68187729a55SMiklos Szeredi * 68287729a55SMiklos Szeredi * For this reason only those processes can call into the filesystem, 68387729a55SMiklos Szeredi * for which the owner of the mount has ptrace privilege. This 68487729a55SMiklos Szeredi * excludes processes started by other users, suid or sgid processes. 68587729a55SMiklos Szeredi */ 68687729a55SMiklos Szeredi static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task) 68787729a55SMiklos Szeredi { 68887729a55SMiklos Szeredi if (fc->flags & FUSE_ALLOW_OTHER) 68987729a55SMiklos Szeredi return 1; 69087729a55SMiklos Szeredi 69187729a55SMiklos Szeredi if (task->euid == fc->user_id && 69287729a55SMiklos Szeredi task->suid == fc->user_id && 69387729a55SMiklos Szeredi task->uid == fc->user_id && 69487729a55SMiklos Szeredi task->egid == fc->group_id && 69587729a55SMiklos Szeredi task->sgid == fc->group_id && 69687729a55SMiklos Szeredi task->gid == fc->group_id) 69787729a55SMiklos Szeredi return 1; 69887729a55SMiklos Szeredi 69987729a55SMiklos Szeredi return 0; 70087729a55SMiklos Szeredi } 70187729a55SMiklos Szeredi 7026f9f1180SMiklos Szeredi /* 7036f9f1180SMiklos Szeredi * Check whether the inode attributes are still valid 7046f9f1180SMiklos Szeredi * 7056f9f1180SMiklos Szeredi * If the attribute validity timeout has expired, then fetch the fresh 7066f9f1180SMiklos Szeredi * attributes with a 'getattr' request 7076f9f1180SMiklos Szeredi * 7086f9f1180SMiklos Szeredi * I'm not sure why cached attributes are never returned for the root 7096f9f1180SMiklos Szeredi * inode, this is probably being too cautious. 7106f9f1180SMiklos Szeredi */ 711e5e5558eSMiklos Szeredi static int fuse_revalidate(struct dentry *entry) 712e5e5558eSMiklos Szeredi { 713e5e5558eSMiklos Szeredi struct inode *inode = entry->d_inode; 714e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 715e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 716e5e5558eSMiklos Szeredi 71787729a55SMiklos Szeredi if (!fuse_allow_task(fc, current)) 718e5e5558eSMiklos Szeredi return -EACCES; 71987729a55SMiklos Szeredi if (get_node_id(inode) != FUSE_ROOT_ID && 7200a0898cfSMiklos Szeredi fi->i_time >= get_jiffies_64()) 721e5e5558eSMiklos Szeredi return 0; 722e5e5558eSMiklos Szeredi 723e5e5558eSMiklos Szeredi return fuse_do_getattr(inode); 724e5e5558eSMiklos Szeredi } 725e5e5558eSMiklos Szeredi 72631d40d74SMiklos Szeredi static int fuse_access(struct inode *inode, int mask) 72731d40d74SMiklos Szeredi { 72831d40d74SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 72931d40d74SMiklos Szeredi struct fuse_req *req; 73031d40d74SMiklos Szeredi struct fuse_access_in inarg; 73131d40d74SMiklos Szeredi int err; 73231d40d74SMiklos Szeredi 73331d40d74SMiklos Szeredi if (fc->no_access) 73431d40d74SMiklos Szeredi return 0; 73531d40d74SMiklos Szeredi 736ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 737ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 738ce1d5a49SMiklos Szeredi return PTR_ERR(req); 73931d40d74SMiklos Szeredi 74031d40d74SMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 74131d40d74SMiklos Szeredi inarg.mask = mask; 74231d40d74SMiklos Szeredi req->in.h.opcode = FUSE_ACCESS; 74331d40d74SMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 74431d40d74SMiklos Szeredi req->in.numargs = 1; 74531d40d74SMiklos Szeredi req->in.args[0].size = sizeof(inarg); 74631d40d74SMiklos Szeredi req->in.args[0].value = &inarg; 74731d40d74SMiklos Szeredi request_send(fc, req); 74831d40d74SMiklos Szeredi err = req->out.h.error; 74931d40d74SMiklos Szeredi fuse_put_request(fc, req); 75031d40d74SMiklos Szeredi if (err == -ENOSYS) { 75131d40d74SMiklos Szeredi fc->no_access = 1; 75231d40d74SMiklos Szeredi err = 0; 75331d40d74SMiklos Szeredi } 75431d40d74SMiklos Szeredi return err; 75531d40d74SMiklos Szeredi } 75631d40d74SMiklos Szeredi 7576f9f1180SMiklos Szeredi /* 7586f9f1180SMiklos Szeredi * Check permission. The two basic access models of FUSE are: 7596f9f1180SMiklos Szeredi * 7606f9f1180SMiklos Szeredi * 1) Local access checking ('default_permissions' mount option) based 7616f9f1180SMiklos Szeredi * on file mode. This is the plain old disk filesystem permission 7626f9f1180SMiklos Szeredi * modell. 7636f9f1180SMiklos Szeredi * 7646f9f1180SMiklos Szeredi * 2) "Remote" access checking, where server is responsible for 7656f9f1180SMiklos Szeredi * checking permission in each inode operation. An exception to this 7666f9f1180SMiklos Szeredi * is if ->permission() was invoked from sys_access() in which case an 7676f9f1180SMiklos Szeredi * access request is sent. Execute permission is still checked 7686f9f1180SMiklos Szeredi * locally based on file mode. 7696f9f1180SMiklos Szeredi */ 770e5e5558eSMiklos Szeredi static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) 771e5e5558eSMiklos Szeredi { 772e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 773e5e5558eSMiklos Szeredi 77487729a55SMiklos Szeredi if (!fuse_allow_task(fc, current)) 775e5e5558eSMiklos Szeredi return -EACCES; 7761e9a4ed9SMiklos Szeredi else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 7771e9a4ed9SMiklos Szeredi int err = generic_permission(inode, mask, NULL); 7781e9a4ed9SMiklos Szeredi 7791e9a4ed9SMiklos Szeredi /* If permission is denied, try to refresh file 7801e9a4ed9SMiklos Szeredi attributes. This is also needed, because the root 7811e9a4ed9SMiklos Szeredi node will at first have no permissions */ 7821e9a4ed9SMiklos Szeredi if (err == -EACCES) { 7831e9a4ed9SMiklos Szeredi err = fuse_do_getattr(inode); 7841e9a4ed9SMiklos Szeredi if (!err) 7851e9a4ed9SMiklos Szeredi err = generic_permission(inode, mask, NULL); 7861e9a4ed9SMiklos Szeredi } 7871e9a4ed9SMiklos Szeredi 7886f9f1180SMiklos Szeredi /* Note: the opposite of the above test does not 7896f9f1180SMiklos Szeredi exist. So if permissions are revoked this won't be 7906f9f1180SMiklos Szeredi noticed immediately, only after the attribute 7916f9f1180SMiklos Szeredi timeout has expired */ 7921e9a4ed9SMiklos Szeredi 7931e9a4ed9SMiklos Szeredi return err; 7941e9a4ed9SMiklos Szeredi } else { 795e5e5558eSMiklos Szeredi int mode = inode->i_mode; 796e5e5558eSMiklos Szeredi if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) 797e5e5558eSMiklos Szeredi return -EACCES; 79831d40d74SMiklos Szeredi 799650a8983SMiklos Szeredi if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR))) 80031d40d74SMiklos Szeredi return fuse_access(inode, mask); 801e5e5558eSMiklos Szeredi return 0; 802e5e5558eSMiklos Szeredi } 803e5e5558eSMiklos Szeredi } 804e5e5558eSMiklos Szeredi 805e5e5558eSMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file, 806e5e5558eSMiklos Szeredi void *dstbuf, filldir_t filldir) 807e5e5558eSMiklos Szeredi { 808e5e5558eSMiklos Szeredi while (nbytes >= FUSE_NAME_OFFSET) { 809e5e5558eSMiklos Szeredi struct fuse_dirent *dirent = (struct fuse_dirent *) buf; 810e5e5558eSMiklos Szeredi size_t reclen = FUSE_DIRENT_SIZE(dirent); 811e5e5558eSMiklos Szeredi int over; 812e5e5558eSMiklos Szeredi if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) 813e5e5558eSMiklos Szeredi return -EIO; 814e5e5558eSMiklos Szeredi if (reclen > nbytes) 815e5e5558eSMiklos Szeredi break; 816e5e5558eSMiklos Szeredi 817e5e5558eSMiklos Szeredi over = filldir(dstbuf, dirent->name, dirent->namelen, 818e5e5558eSMiklos Szeredi file->f_pos, dirent->ino, dirent->type); 819e5e5558eSMiklos Szeredi if (over) 820e5e5558eSMiklos Szeredi break; 821e5e5558eSMiklos Szeredi 822e5e5558eSMiklos Szeredi buf += reclen; 823e5e5558eSMiklos Szeredi nbytes -= reclen; 824e5e5558eSMiklos Szeredi file->f_pos = dirent->off; 825e5e5558eSMiklos Szeredi } 826e5e5558eSMiklos Szeredi 827e5e5558eSMiklos Szeredi return 0; 828e5e5558eSMiklos Szeredi } 829e5e5558eSMiklos Szeredi 830e5e5558eSMiklos Szeredi static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) 831e5e5558eSMiklos Szeredi { 83204730fefSMiklos Szeredi int err; 83304730fefSMiklos Szeredi size_t nbytes; 83404730fefSMiklos Szeredi struct page *page; 83504730fefSMiklos Szeredi struct inode *inode = file->f_dentry->d_inode; 83604730fefSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 837248d86e8SMiklos Szeredi struct fuse_req *req; 838248d86e8SMiklos Szeredi 839248d86e8SMiklos Szeredi if (is_bad_inode(inode)) 840248d86e8SMiklos Szeredi return -EIO; 841248d86e8SMiklos Szeredi 842ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 843ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 844ce1d5a49SMiklos Szeredi return PTR_ERR(req); 845e5e5558eSMiklos Szeredi 84604730fefSMiklos Szeredi page = alloc_page(GFP_KERNEL); 84704730fefSMiklos Szeredi if (!page) { 84804730fefSMiklos Szeredi fuse_put_request(fc, req); 849e5e5558eSMiklos Szeredi return -ENOMEM; 85004730fefSMiklos Szeredi } 85104730fefSMiklos Szeredi req->num_pages = 1; 85204730fefSMiklos Szeredi req->pages[0] = page; 853361b1eb5SMiklos Szeredi fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR); 854361b1eb5SMiklos Szeredi request_send(fc, req); 855361b1eb5SMiklos Szeredi nbytes = req->out.args[0].size; 85604730fefSMiklos Szeredi err = req->out.h.error; 85704730fefSMiklos Szeredi fuse_put_request(fc, req); 85804730fefSMiklos Szeredi if (!err) 85904730fefSMiklos Szeredi err = parse_dirfile(page_address(page), nbytes, file, dstbuf, 86004730fefSMiklos Szeredi filldir); 861e5e5558eSMiklos Szeredi 86204730fefSMiklos Szeredi __free_page(page); 863b36c31baSMiklos Szeredi fuse_invalidate_attr(inode); /* atime changed */ 86404730fefSMiklos Szeredi return err; 865e5e5558eSMiklos Szeredi } 866e5e5558eSMiklos Szeredi 867e5e5558eSMiklos Szeredi static char *read_link(struct dentry *dentry) 868e5e5558eSMiklos Szeredi { 869e5e5558eSMiklos Szeredi struct inode *inode = dentry->d_inode; 870e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 871ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 872e5e5558eSMiklos Szeredi char *link; 873e5e5558eSMiklos Szeredi 874ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 875ce1d5a49SMiklos Szeredi return ERR_PTR(PTR_ERR(req)); 876e5e5558eSMiklos Szeredi 877e5e5558eSMiklos Szeredi link = (char *) __get_free_page(GFP_KERNEL); 878e5e5558eSMiklos Szeredi if (!link) { 879e5e5558eSMiklos Szeredi link = ERR_PTR(-ENOMEM); 880e5e5558eSMiklos Szeredi goto out; 881e5e5558eSMiklos Szeredi } 882e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_READLINK; 883e5e5558eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 884e5e5558eSMiklos Szeredi req->out.argvar = 1; 885e5e5558eSMiklos Szeredi req->out.numargs = 1; 886e5e5558eSMiklos Szeredi req->out.args[0].size = PAGE_SIZE - 1; 887e5e5558eSMiklos Szeredi req->out.args[0].value = link; 888e5e5558eSMiklos Szeredi request_send(fc, req); 889e5e5558eSMiklos Szeredi if (req->out.h.error) { 890e5e5558eSMiklos Szeredi free_page((unsigned long) link); 891e5e5558eSMiklos Szeredi link = ERR_PTR(req->out.h.error); 892e5e5558eSMiklos Szeredi } else 893e5e5558eSMiklos Szeredi link[req->out.args[0].size] = '\0'; 894e5e5558eSMiklos Szeredi out: 895e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 896b36c31baSMiklos Szeredi fuse_invalidate_attr(inode); /* atime changed */ 897e5e5558eSMiklos Szeredi return link; 898e5e5558eSMiklos Szeredi } 899e5e5558eSMiklos Szeredi 900e5e5558eSMiklos Szeredi static void free_link(char *link) 901e5e5558eSMiklos Szeredi { 902e5e5558eSMiklos Szeredi if (!IS_ERR(link)) 903e5e5558eSMiklos Szeredi free_page((unsigned long) link); 904e5e5558eSMiklos Szeredi } 905e5e5558eSMiklos Szeredi 906e5e5558eSMiklos Szeredi static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd) 907e5e5558eSMiklos Szeredi { 908e5e5558eSMiklos Szeredi nd_set_link(nd, read_link(dentry)); 909e5e5558eSMiklos Szeredi return NULL; 910e5e5558eSMiklos Szeredi } 911e5e5558eSMiklos Szeredi 912e5e5558eSMiklos Szeredi static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c) 913e5e5558eSMiklos Szeredi { 914e5e5558eSMiklos Szeredi free_link(nd_get_link(nd)); 915e5e5558eSMiklos Szeredi } 916e5e5558eSMiklos Szeredi 917e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file) 918e5e5558eSMiklos Szeredi { 91904730fefSMiklos Szeredi return fuse_open_common(inode, file, 1); 920e5e5558eSMiklos Szeredi } 921e5e5558eSMiklos Szeredi 922e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file) 923e5e5558eSMiklos Szeredi { 92404730fefSMiklos Szeredi return fuse_release_common(inode, file, 1); 925e5e5558eSMiklos Szeredi } 926e5e5558eSMiklos Szeredi 92782547981SMiklos Szeredi static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync) 92882547981SMiklos Szeredi { 92982547981SMiklos Szeredi /* nfsd can call this with no file */ 93082547981SMiklos Szeredi return file ? fuse_fsync_common(file, de, datasync, 1) : 0; 93182547981SMiklos Szeredi } 93282547981SMiklos Szeredi 933befc649cSMiklos Szeredi static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) 9349e6268dbSMiklos Szeredi { 9359e6268dbSMiklos Szeredi unsigned ivalid = iattr->ia_valid; 9369e6268dbSMiklos Szeredi 9379e6268dbSMiklos Szeredi if (ivalid & ATTR_MODE) 938befc649cSMiklos Szeredi arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode; 9399e6268dbSMiklos Szeredi if (ivalid & ATTR_UID) 940befc649cSMiklos Szeredi arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid; 9419e6268dbSMiklos Szeredi if (ivalid & ATTR_GID) 942befc649cSMiklos Szeredi arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid; 9439e6268dbSMiklos Szeredi if (ivalid & ATTR_SIZE) 944befc649cSMiklos Szeredi arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size; 9459e6268dbSMiklos Szeredi /* You can only _set_ these together (they may change by themselves) */ 9469e6268dbSMiklos Szeredi if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) { 947befc649cSMiklos Szeredi arg->valid |= FATTR_ATIME | FATTR_MTIME; 948befc649cSMiklos Szeredi arg->atime = iattr->ia_atime.tv_sec; 949befc649cSMiklos Szeredi arg->mtime = iattr->ia_mtime.tv_sec; 9509e6268dbSMiklos Szeredi } 951befc649cSMiklos Szeredi if (ivalid & ATTR_FILE) { 952befc649cSMiklos Szeredi struct fuse_file *ff = iattr->ia_file->private_data; 953befc649cSMiklos Szeredi arg->valid |= FATTR_FH; 954befc649cSMiklos Szeredi arg->fh = ff->fh; 955befc649cSMiklos Szeredi } 9569e6268dbSMiklos Szeredi } 9579e6268dbSMiklos Szeredi 9589ffbb916SMiklos Szeredi static void fuse_vmtruncate(struct inode *inode, loff_t offset) 9599ffbb916SMiklos Szeredi { 9609ffbb916SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 9619ffbb916SMiklos Szeredi int need_trunc; 9629ffbb916SMiklos Szeredi 9639ffbb916SMiklos Szeredi spin_lock(&fc->lock); 9649ffbb916SMiklos Szeredi need_trunc = inode->i_size > offset; 9659ffbb916SMiklos Szeredi i_size_write(inode, offset); 9669ffbb916SMiklos Szeredi spin_unlock(&fc->lock); 9679ffbb916SMiklos Szeredi 9689ffbb916SMiklos Szeredi if (need_trunc) { 9699ffbb916SMiklos Szeredi struct address_space *mapping = inode->i_mapping; 9709ffbb916SMiklos Szeredi unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); 9719ffbb916SMiklos Szeredi truncate_inode_pages(mapping, offset); 9729ffbb916SMiklos Szeredi } 9739ffbb916SMiklos Szeredi } 9749ffbb916SMiklos Szeredi 9756f9f1180SMiklos Szeredi /* 9766f9f1180SMiklos Szeredi * Set attributes, and at the same time refresh them. 9776f9f1180SMiklos Szeredi * 9786f9f1180SMiklos Szeredi * Truncation is slightly complicated, because the 'truncate' request 9796f9f1180SMiklos Szeredi * may fail, in which case we don't want to touch the mapping. 9809ffbb916SMiklos Szeredi * vmtruncate() doesn't allow for this case, so do the rlimit checking 9819ffbb916SMiklos Szeredi * and the actual truncation by hand. 9826f9f1180SMiklos Szeredi */ 9839e6268dbSMiklos Szeredi static int fuse_setattr(struct dentry *entry, struct iattr *attr) 9849e6268dbSMiklos Szeredi { 9859e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 9869e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 9879e6268dbSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 9889e6268dbSMiklos Szeredi struct fuse_req *req; 9899e6268dbSMiklos Szeredi struct fuse_setattr_in inarg; 9909e6268dbSMiklos Szeredi struct fuse_attr_out outarg; 9919e6268dbSMiklos Szeredi int err; 9929e6268dbSMiklos Szeredi int is_truncate = 0; 9939e6268dbSMiklos Szeredi 9941e9a4ed9SMiklos Szeredi if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 9951e9a4ed9SMiklos Szeredi err = inode_change_ok(inode, attr); 9961e9a4ed9SMiklos Szeredi if (err) 9971e9a4ed9SMiklos Szeredi return err; 9981e9a4ed9SMiklos Szeredi } 9991e9a4ed9SMiklos Szeredi 10009e6268dbSMiklos Szeredi if (attr->ia_valid & ATTR_SIZE) { 10019e6268dbSMiklos Szeredi unsigned long limit; 10029e6268dbSMiklos Szeredi is_truncate = 1; 10039e6268dbSMiklos Szeredi limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; 10049e6268dbSMiklos Szeredi if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) { 10059e6268dbSMiklos Szeredi send_sig(SIGXFSZ, current, 0); 10069e6268dbSMiklos Szeredi return -EFBIG; 10079e6268dbSMiklos Szeredi } 10089e6268dbSMiklos Szeredi } 10099e6268dbSMiklos Szeredi 1010ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1011ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1012ce1d5a49SMiklos Szeredi return PTR_ERR(req); 10139e6268dbSMiklos Szeredi 10149e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 1015befc649cSMiklos Szeredi iattr_to_fattr(attr, &inarg); 10169e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_SETATTR; 10179e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 10189e6268dbSMiklos Szeredi req->in.numargs = 1; 10199e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 10209e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 10219e6268dbSMiklos Szeredi req->out.numargs = 1; 10229e6268dbSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 10239e6268dbSMiklos Szeredi req->out.args[0].value = &outarg; 10249e6268dbSMiklos Szeredi request_send(fc, req); 10259e6268dbSMiklos Szeredi err = req->out.h.error; 10269e6268dbSMiklos Szeredi fuse_put_request(fc, req); 10279e6268dbSMiklos Szeredi if (!err) { 10289e6268dbSMiklos Szeredi if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { 10299e6268dbSMiklos Szeredi make_bad_inode(inode); 10309e6268dbSMiklos Szeredi err = -EIO; 10319e6268dbSMiklos Szeredi } else { 10329ffbb916SMiklos Szeredi if (is_truncate) 10339ffbb916SMiklos Szeredi fuse_vmtruncate(inode, outarg.attr.size); 10349e6268dbSMiklos Szeredi fuse_change_attributes(inode, &outarg.attr); 10359e6268dbSMiklos Szeredi fi->i_time = time_to_jiffies(outarg.attr_valid, 10369e6268dbSMiklos Szeredi outarg.attr_valid_nsec); 10379e6268dbSMiklos Szeredi } 10389e6268dbSMiklos Szeredi } else if (err == -EINTR) 10399e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 10409e6268dbSMiklos Szeredi 10419e6268dbSMiklos Szeredi return err; 10429e6268dbSMiklos Szeredi } 10439e6268dbSMiklos Szeredi 1044e5e5558eSMiklos Szeredi static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, 1045e5e5558eSMiklos Szeredi struct kstat *stat) 1046e5e5558eSMiklos Szeredi { 1047e5e5558eSMiklos Szeredi struct inode *inode = entry->d_inode; 1048e5e5558eSMiklos Szeredi int err = fuse_revalidate(entry); 1049e5e5558eSMiklos Szeredi if (!err) 1050e5e5558eSMiklos Szeredi generic_fillattr(inode, stat); 1051e5e5558eSMiklos Szeredi 1052e5e5558eSMiklos Szeredi return err; 1053e5e5558eSMiklos Szeredi } 1054e5e5558eSMiklos Szeredi 105592a8780eSMiklos Szeredi static int fuse_setxattr(struct dentry *entry, const char *name, 105692a8780eSMiklos Szeredi const void *value, size_t size, int flags) 105792a8780eSMiklos Szeredi { 105892a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 105992a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 106092a8780eSMiklos Szeredi struct fuse_req *req; 106192a8780eSMiklos Szeredi struct fuse_setxattr_in inarg; 106292a8780eSMiklos Szeredi int err; 106392a8780eSMiklos Szeredi 106492a8780eSMiklos Szeredi if (fc->no_setxattr) 106592a8780eSMiklos Szeredi return -EOPNOTSUPP; 106692a8780eSMiklos Szeredi 1067ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1068ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1069ce1d5a49SMiklos Szeredi return PTR_ERR(req); 107092a8780eSMiklos Szeredi 107192a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 107292a8780eSMiklos Szeredi inarg.size = size; 107392a8780eSMiklos Szeredi inarg.flags = flags; 107492a8780eSMiklos Szeredi req->in.h.opcode = FUSE_SETXATTR; 107592a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 107692a8780eSMiklos Szeredi req->in.numargs = 3; 107792a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 107892a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 107992a8780eSMiklos Szeredi req->in.args[1].size = strlen(name) + 1; 108092a8780eSMiklos Szeredi req->in.args[1].value = name; 108192a8780eSMiklos Szeredi req->in.args[2].size = size; 108292a8780eSMiklos Szeredi req->in.args[2].value = value; 108392a8780eSMiklos Szeredi request_send(fc, req); 108492a8780eSMiklos Szeredi err = req->out.h.error; 108592a8780eSMiklos Szeredi fuse_put_request(fc, req); 108692a8780eSMiklos Szeredi if (err == -ENOSYS) { 108792a8780eSMiklos Szeredi fc->no_setxattr = 1; 108892a8780eSMiklos Szeredi err = -EOPNOTSUPP; 108992a8780eSMiklos Szeredi } 109092a8780eSMiklos Szeredi return err; 109192a8780eSMiklos Szeredi } 109292a8780eSMiklos Szeredi 109392a8780eSMiklos Szeredi static ssize_t fuse_getxattr(struct dentry *entry, const char *name, 109492a8780eSMiklos Szeredi void *value, size_t size) 109592a8780eSMiklos Szeredi { 109692a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 109792a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 109892a8780eSMiklos Szeredi struct fuse_req *req; 109992a8780eSMiklos Szeredi struct fuse_getxattr_in inarg; 110092a8780eSMiklos Szeredi struct fuse_getxattr_out outarg; 110192a8780eSMiklos Szeredi ssize_t ret; 110292a8780eSMiklos Szeredi 110392a8780eSMiklos Szeredi if (fc->no_getxattr) 110492a8780eSMiklos Szeredi return -EOPNOTSUPP; 110592a8780eSMiklos Szeredi 1106ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1107ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1108ce1d5a49SMiklos Szeredi return PTR_ERR(req); 110992a8780eSMiklos Szeredi 111092a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 111192a8780eSMiklos Szeredi inarg.size = size; 111292a8780eSMiklos Szeredi req->in.h.opcode = FUSE_GETXATTR; 111392a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 111492a8780eSMiklos Szeredi req->in.numargs = 2; 111592a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 111692a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 111792a8780eSMiklos Szeredi req->in.args[1].size = strlen(name) + 1; 111892a8780eSMiklos Szeredi req->in.args[1].value = name; 111992a8780eSMiklos Szeredi /* This is really two different operations rolled into one */ 112092a8780eSMiklos Szeredi req->out.numargs = 1; 112192a8780eSMiklos Szeredi if (size) { 112292a8780eSMiklos Szeredi req->out.argvar = 1; 112392a8780eSMiklos Szeredi req->out.args[0].size = size; 112492a8780eSMiklos Szeredi req->out.args[0].value = value; 112592a8780eSMiklos Szeredi } else { 112692a8780eSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 112792a8780eSMiklos Szeredi req->out.args[0].value = &outarg; 112892a8780eSMiklos Szeredi } 112992a8780eSMiklos Szeredi request_send(fc, req); 113092a8780eSMiklos Szeredi ret = req->out.h.error; 113192a8780eSMiklos Szeredi if (!ret) 113292a8780eSMiklos Szeredi ret = size ? req->out.args[0].size : outarg.size; 113392a8780eSMiklos Szeredi else { 113492a8780eSMiklos Szeredi if (ret == -ENOSYS) { 113592a8780eSMiklos Szeredi fc->no_getxattr = 1; 113692a8780eSMiklos Szeredi ret = -EOPNOTSUPP; 113792a8780eSMiklos Szeredi } 113892a8780eSMiklos Szeredi } 113992a8780eSMiklos Szeredi fuse_put_request(fc, req); 114092a8780eSMiklos Szeredi return ret; 114192a8780eSMiklos Szeredi } 114292a8780eSMiklos Szeredi 114392a8780eSMiklos Szeredi static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) 114492a8780eSMiklos Szeredi { 114592a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 114692a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 114792a8780eSMiklos Szeredi struct fuse_req *req; 114892a8780eSMiklos Szeredi struct fuse_getxattr_in inarg; 114992a8780eSMiklos Szeredi struct fuse_getxattr_out outarg; 115092a8780eSMiklos Szeredi ssize_t ret; 115192a8780eSMiklos Szeredi 115292a8780eSMiklos Szeredi if (fc->no_listxattr) 115392a8780eSMiklos Szeredi return -EOPNOTSUPP; 115492a8780eSMiklos Szeredi 1155ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1156ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1157ce1d5a49SMiklos Szeredi return PTR_ERR(req); 115892a8780eSMiklos Szeredi 115992a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 116092a8780eSMiklos Szeredi inarg.size = size; 116192a8780eSMiklos Szeredi req->in.h.opcode = FUSE_LISTXATTR; 116292a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 116392a8780eSMiklos Szeredi req->in.numargs = 1; 116492a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 116592a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 116692a8780eSMiklos Szeredi /* This is really two different operations rolled into one */ 116792a8780eSMiklos Szeredi req->out.numargs = 1; 116892a8780eSMiklos Szeredi if (size) { 116992a8780eSMiklos Szeredi req->out.argvar = 1; 117092a8780eSMiklos Szeredi req->out.args[0].size = size; 117192a8780eSMiklos Szeredi req->out.args[0].value = list; 117292a8780eSMiklos Szeredi } else { 117392a8780eSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 117492a8780eSMiklos Szeredi req->out.args[0].value = &outarg; 117592a8780eSMiklos Szeredi } 117692a8780eSMiklos Szeredi request_send(fc, req); 117792a8780eSMiklos Szeredi ret = req->out.h.error; 117892a8780eSMiklos Szeredi if (!ret) 117992a8780eSMiklos Szeredi ret = size ? req->out.args[0].size : outarg.size; 118092a8780eSMiklos Szeredi else { 118192a8780eSMiklos Szeredi if (ret == -ENOSYS) { 118292a8780eSMiklos Szeredi fc->no_listxattr = 1; 118392a8780eSMiklos Szeredi ret = -EOPNOTSUPP; 118492a8780eSMiklos Szeredi } 118592a8780eSMiklos Szeredi } 118692a8780eSMiklos Szeredi fuse_put_request(fc, req); 118792a8780eSMiklos Szeredi return ret; 118892a8780eSMiklos Szeredi } 118992a8780eSMiklos Szeredi 119092a8780eSMiklos Szeredi static int fuse_removexattr(struct dentry *entry, const char *name) 119192a8780eSMiklos Szeredi { 119292a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 119392a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 119492a8780eSMiklos Szeredi struct fuse_req *req; 119592a8780eSMiklos Szeredi int err; 119692a8780eSMiklos Szeredi 119792a8780eSMiklos Szeredi if (fc->no_removexattr) 119892a8780eSMiklos Szeredi return -EOPNOTSUPP; 119992a8780eSMiklos Szeredi 1200ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1201ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1202ce1d5a49SMiklos Szeredi return PTR_ERR(req); 120392a8780eSMiklos Szeredi 120492a8780eSMiklos Szeredi req->in.h.opcode = FUSE_REMOVEXATTR; 120592a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 120692a8780eSMiklos Szeredi req->in.numargs = 1; 120792a8780eSMiklos Szeredi req->in.args[0].size = strlen(name) + 1; 120892a8780eSMiklos Szeredi req->in.args[0].value = name; 120992a8780eSMiklos Szeredi request_send(fc, req); 121092a8780eSMiklos Szeredi err = req->out.h.error; 121192a8780eSMiklos Szeredi fuse_put_request(fc, req); 121292a8780eSMiklos Szeredi if (err == -ENOSYS) { 121392a8780eSMiklos Szeredi fc->no_removexattr = 1; 121492a8780eSMiklos Szeredi err = -EOPNOTSUPP; 121592a8780eSMiklos Szeredi } 121692a8780eSMiklos Szeredi return err; 121792a8780eSMiklos Szeredi } 121892a8780eSMiklos Szeredi 1219e5e5558eSMiklos Szeredi static struct inode_operations fuse_dir_inode_operations = { 1220e5e5558eSMiklos Szeredi .lookup = fuse_lookup, 12219e6268dbSMiklos Szeredi .mkdir = fuse_mkdir, 12229e6268dbSMiklos Szeredi .symlink = fuse_symlink, 12239e6268dbSMiklos Szeredi .unlink = fuse_unlink, 12249e6268dbSMiklos Szeredi .rmdir = fuse_rmdir, 12259e6268dbSMiklos Szeredi .rename = fuse_rename, 12269e6268dbSMiklos Szeredi .link = fuse_link, 12279e6268dbSMiklos Szeredi .setattr = fuse_setattr, 12289e6268dbSMiklos Szeredi .create = fuse_create, 12299e6268dbSMiklos Szeredi .mknod = fuse_mknod, 1230e5e5558eSMiklos Szeredi .permission = fuse_permission, 1231e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 123292a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 123392a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 123492a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 123592a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 1236e5e5558eSMiklos Szeredi }; 1237e5e5558eSMiklos Szeredi 12384b6f5d20SArjan van de Ven static const struct file_operations fuse_dir_operations = { 1239b6aeadedSMiklos Szeredi .llseek = generic_file_llseek, 1240e5e5558eSMiklos Szeredi .read = generic_read_dir, 1241e5e5558eSMiklos Szeredi .readdir = fuse_readdir, 1242e5e5558eSMiklos Szeredi .open = fuse_dir_open, 1243e5e5558eSMiklos Szeredi .release = fuse_dir_release, 124482547981SMiklos Szeredi .fsync = fuse_dir_fsync, 1245e5e5558eSMiklos Szeredi }; 1246e5e5558eSMiklos Szeredi 1247e5e5558eSMiklos Szeredi static struct inode_operations fuse_common_inode_operations = { 12489e6268dbSMiklos Szeredi .setattr = fuse_setattr, 1249e5e5558eSMiklos Szeredi .permission = fuse_permission, 1250e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 125192a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 125292a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 125392a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 125492a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 1255e5e5558eSMiklos Szeredi }; 1256e5e5558eSMiklos Szeredi 1257e5e5558eSMiklos Szeredi static struct inode_operations fuse_symlink_inode_operations = { 12589e6268dbSMiklos Szeredi .setattr = fuse_setattr, 1259e5e5558eSMiklos Szeredi .follow_link = fuse_follow_link, 1260e5e5558eSMiklos Szeredi .put_link = fuse_put_link, 1261e5e5558eSMiklos Szeredi .readlink = generic_readlink, 1262e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 126392a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 126492a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 126592a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 126692a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 1267e5e5558eSMiklos Szeredi }; 1268e5e5558eSMiklos Szeredi 1269e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode) 1270e5e5558eSMiklos Szeredi { 1271e5e5558eSMiklos Szeredi inode->i_op = &fuse_common_inode_operations; 1272e5e5558eSMiklos Szeredi } 1273e5e5558eSMiklos Szeredi 1274e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode) 1275e5e5558eSMiklos Szeredi { 1276e5e5558eSMiklos Szeredi inode->i_op = &fuse_dir_inode_operations; 1277e5e5558eSMiklos Szeredi inode->i_fop = &fuse_dir_operations; 1278e5e5558eSMiklos Szeredi } 1279e5e5558eSMiklos Szeredi 1280e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode) 1281e5e5558eSMiklos Szeredi { 1282e5e5558eSMiklos Szeredi inode->i_op = &fuse_symlink_inode_operations; 1283e5e5558eSMiklos Szeredi } 1284