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 } 1669e6268dbSMiklos Szeredi fi->nlookup ++; 1679e6268dbSMiklos Szeredi } 168e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 1699e6268dbSMiklos Szeredi if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) 170e5e5558eSMiklos Szeredi return 0; 171e5e5558eSMiklos Szeredi 172e5e5558eSMiklos Szeredi fuse_change_attributes(inode, &outarg.attr); 1730aa7c699SMiklos Szeredi fuse_change_timeout(entry, &outarg); 174e5e5558eSMiklos Szeredi } 175e5e5558eSMiklos Szeredi return 1; 176e5e5558eSMiklos Szeredi } 177e5e5558eSMiklos Szeredi 1786f9f1180SMiklos Szeredi /* 1796f9f1180SMiklos Szeredi * Check if there's already a hashed alias of this directory inode. 1806f9f1180SMiklos Szeredi * If yes, then lookup and mkdir must not create a new alias. 1816f9f1180SMiklos Szeredi */ 182f007d5c9SMiklos Szeredi static int dir_alias(struct inode *inode) 183f007d5c9SMiklos Szeredi { 184f007d5c9SMiklos Szeredi if (S_ISDIR(inode->i_mode)) { 185f007d5c9SMiklos Szeredi struct dentry *alias = d_find_alias(inode); 186f007d5c9SMiklos Szeredi if (alias) { 187f007d5c9SMiklos Szeredi dput(alias); 188f007d5c9SMiklos Szeredi return 1; 189f007d5c9SMiklos Szeredi } 190f007d5c9SMiklos Szeredi } 191f007d5c9SMiklos Szeredi return 0; 192f007d5c9SMiklos Szeredi } 193f007d5c9SMiklos Szeredi 1948bfc016dSMiklos Szeredi static int invalid_nodeid(u64 nodeid) 1952827d0b2SMiklos Szeredi { 1962827d0b2SMiklos Szeredi return !nodeid || nodeid == FUSE_ROOT_ID; 1972827d0b2SMiklos Szeredi } 1982827d0b2SMiklos Szeredi 199e5e5558eSMiklos Szeredi static struct dentry_operations fuse_dentry_operations = { 200e5e5558eSMiklos Szeredi .d_revalidate = fuse_dentry_revalidate, 201e5e5558eSMiklos Szeredi }; 202e5e5558eSMiklos Szeredi 2038bfc016dSMiklos Szeredi static int valid_mode(int m) 20439ee059aSMiklos Szeredi { 20539ee059aSMiklos Szeredi return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) || 20639ee059aSMiklos Szeredi S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); 20739ee059aSMiklos Szeredi } 20839ee059aSMiklos Szeredi 2090aa7c699SMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, 2100aa7c699SMiklos Szeredi struct nameidata *nd) 211e5e5558eSMiklos Szeredi { 212e5e5558eSMiklos Szeredi int err; 213e5e5558eSMiklos Szeredi struct fuse_entry_out outarg; 214e5e5558eSMiklos Szeredi struct inode *inode = NULL; 215e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 216e5e5558eSMiklos Szeredi struct fuse_req *req; 217e5e5558eSMiklos Szeredi 218e5e5558eSMiklos Szeredi if (entry->d_name.len > FUSE_NAME_MAX) 2190aa7c699SMiklos Szeredi return ERR_PTR(-ENAMETOOLONG); 220e5e5558eSMiklos Szeredi 221ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 222ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 223ce1d5a49SMiklos Szeredi return ERR_PTR(PTR_ERR(req)); 224e5e5558eSMiklos Szeredi 225e5e5558eSMiklos Szeredi fuse_lookup_init(req, dir, entry, &outarg); 226e5e5558eSMiklos Szeredi request_send(fc, req); 227e5e5558eSMiklos Szeredi err = req->out.h.error; 22850322fe7SMiklos Szeredi /* Zero nodeid is same as -ENOENT, but with valid timeout */ 22950322fe7SMiklos Szeredi if (!err && outarg.nodeid && 23050322fe7SMiklos Szeredi (invalid_nodeid(outarg.nodeid) || !valid_mode(outarg.attr.mode))) 231ee4e5271SMiklos Szeredi err = -EIO; 2328cbdf1e6SMiklos Szeredi if (!err && outarg.nodeid) { 233e5e5558eSMiklos Szeredi inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 2349e6268dbSMiklos Szeredi &outarg.attr); 235e5e5558eSMiklos Szeredi if (!inode) { 2369e6268dbSMiklos Szeredi fuse_send_forget(fc, req, outarg.nodeid, 1); 2370aa7c699SMiklos Szeredi return ERR_PTR(-ENOMEM); 238e5e5558eSMiklos Szeredi } 239e5e5558eSMiklos Szeredi } 240e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 241e5e5558eSMiklos Szeredi if (err && err != -ENOENT) 2420aa7c699SMiklos Szeredi return ERR_PTR(err); 243e5e5558eSMiklos Szeredi 2440aa7c699SMiklos Szeredi if (inode && dir_alias(inode)) { 2450aa7c699SMiklos Szeredi iput(inode); 2460aa7c699SMiklos Szeredi return ERR_PTR(-EIO); 247e5e5558eSMiklos Szeredi } 2480aa7c699SMiklos Szeredi d_add(entry, inode); 249e5e5558eSMiklos Szeredi entry->d_op = &fuse_dentry_operations; 2508cbdf1e6SMiklos Szeredi if (!err) 2510aa7c699SMiklos Szeredi fuse_change_timeout(entry, &outarg); 2528cbdf1e6SMiklos Szeredi else 2538cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 2540aa7c699SMiklos Szeredi return NULL; 255e5e5558eSMiklos Szeredi } 256e5e5558eSMiklos Szeredi 2576f9f1180SMiklos Szeredi /* 25851eb01e7SMiklos Szeredi * Synchronous release for the case when something goes wrong in CREATE_OPEN 25951eb01e7SMiklos Szeredi */ 26051eb01e7SMiklos Szeredi static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff, 26151eb01e7SMiklos Szeredi u64 nodeid, int flags) 26251eb01e7SMiklos Szeredi { 26351eb01e7SMiklos Szeredi struct fuse_req *req; 26451eb01e7SMiklos Szeredi 26551eb01e7SMiklos Szeredi req = fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE); 26651eb01e7SMiklos Szeredi req->force = 1; 26751eb01e7SMiklos Szeredi request_send(fc, req); 26851eb01e7SMiklos Szeredi fuse_put_request(fc, req); 26951eb01e7SMiklos Szeredi } 27051eb01e7SMiklos Szeredi 27151eb01e7SMiklos Szeredi /* 2726f9f1180SMiklos Szeredi * Atomic create+open operation 2736f9f1180SMiklos Szeredi * 2746f9f1180SMiklos Szeredi * If the filesystem doesn't support this, then fall back to separate 2756f9f1180SMiklos Szeredi * 'mknod' + 'open' requests. 2766f9f1180SMiklos Szeredi */ 277fd72faacSMiklos Szeredi static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, 278fd72faacSMiklos Szeredi struct nameidata *nd) 279fd72faacSMiklos Szeredi { 280fd72faacSMiklos Szeredi int err; 281fd72faacSMiklos Szeredi struct inode *inode; 282fd72faacSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 283fd72faacSMiklos Szeredi struct fuse_req *req; 28451eb01e7SMiklos Szeredi struct fuse_req *forget_req; 285fd72faacSMiklos Szeredi struct fuse_open_in inarg; 286fd72faacSMiklos Szeredi struct fuse_open_out outopen; 287fd72faacSMiklos Szeredi struct fuse_entry_out outentry; 288fd72faacSMiklos Szeredi struct fuse_file *ff; 289fd72faacSMiklos Szeredi struct file *file; 290fd72faacSMiklos Szeredi int flags = nd->intent.open.flags - 1; 291fd72faacSMiklos Szeredi 292fd72faacSMiklos Szeredi if (fc->no_create) 293ce1d5a49SMiklos Szeredi return -ENOSYS; 294fd72faacSMiklos Szeredi 29551eb01e7SMiklos Szeredi forget_req = fuse_get_req(fc); 29651eb01e7SMiklos Szeredi if (IS_ERR(forget_req)) 29751eb01e7SMiklos Szeredi return PTR_ERR(forget_req); 29851eb01e7SMiklos Szeredi 299ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 30051eb01e7SMiklos Szeredi err = PTR_ERR(req); 301ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 30251eb01e7SMiklos Szeredi goto out_put_forget_req; 303fd72faacSMiklos Szeredi 304ce1d5a49SMiklos Szeredi err = -ENOMEM; 305fd72faacSMiklos Szeredi ff = fuse_file_alloc(); 306fd72faacSMiklos Szeredi if (!ff) 307fd72faacSMiklos Szeredi goto out_put_request; 308fd72faacSMiklos Szeredi 309fd72faacSMiklos Szeredi flags &= ~O_NOCTTY; 310fd72faacSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 311fd72faacSMiklos Szeredi inarg.flags = flags; 312fd72faacSMiklos Szeredi inarg.mode = mode; 313fd72faacSMiklos Szeredi req->in.h.opcode = FUSE_CREATE; 314fd72faacSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 315fd72faacSMiklos Szeredi req->in.numargs = 2; 316fd72faacSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 317fd72faacSMiklos Szeredi req->in.args[0].value = &inarg; 318fd72faacSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 319fd72faacSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 320fd72faacSMiklos Szeredi req->out.numargs = 2; 321fd72faacSMiklos Szeredi req->out.args[0].size = sizeof(outentry); 322fd72faacSMiklos Szeredi req->out.args[0].value = &outentry; 323fd72faacSMiklos Szeredi req->out.args[1].size = sizeof(outopen); 324fd72faacSMiklos Szeredi req->out.args[1].value = &outopen; 325fd72faacSMiklos Szeredi request_send(fc, req); 326fd72faacSMiklos Szeredi err = req->out.h.error; 327fd72faacSMiklos Szeredi if (err) { 328fd72faacSMiklos Szeredi if (err == -ENOSYS) 329fd72faacSMiklos Szeredi fc->no_create = 1; 330fd72faacSMiklos Szeredi goto out_free_ff; 331fd72faacSMiklos Szeredi } 332fd72faacSMiklos Szeredi 333fd72faacSMiklos Szeredi err = -EIO; 3342827d0b2SMiklos Szeredi if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid)) 335fd72faacSMiklos Szeredi goto out_free_ff; 336fd72faacSMiklos Szeredi 33751eb01e7SMiklos Szeredi fuse_put_request(fc, req); 338fd72faacSMiklos Szeredi inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, 339fd72faacSMiklos Szeredi &outentry.attr); 340fd72faacSMiklos Szeredi if (!inode) { 341fd72faacSMiklos Szeredi flags &= ~(O_CREAT | O_EXCL | O_TRUNC); 342fd72faacSMiklos Szeredi ff->fh = outopen.fh; 34351eb01e7SMiklos Szeredi fuse_sync_release(fc, ff, outentry.nodeid, flags); 34451eb01e7SMiklos Szeredi fuse_send_forget(fc, forget_req, outentry.nodeid, 1); 34551eb01e7SMiklos Szeredi return -ENOMEM; 346fd72faacSMiklos Szeredi } 34751eb01e7SMiklos Szeredi fuse_put_request(fc, forget_req); 348fd72faacSMiklos Szeredi d_instantiate(entry, inode); 3490aa7c699SMiklos Szeredi fuse_change_timeout(entry, &outentry); 350fd72faacSMiklos Szeredi file = lookup_instantiate_filp(nd, entry, generic_file_open); 351fd72faacSMiklos Szeredi if (IS_ERR(file)) { 352fd72faacSMiklos Szeredi ff->fh = outopen.fh; 35351eb01e7SMiklos Szeredi fuse_sync_release(fc, ff, outentry.nodeid, flags); 354fd72faacSMiklos Szeredi return PTR_ERR(file); 355fd72faacSMiklos Szeredi } 356fd72faacSMiklos Szeredi fuse_finish_open(inode, file, ff, &outopen); 357fd72faacSMiklos Szeredi return 0; 358fd72faacSMiklos Szeredi 359fd72faacSMiklos Szeredi out_free_ff: 360fd72faacSMiklos Szeredi fuse_file_free(ff); 361fd72faacSMiklos Szeredi out_put_request: 362fd72faacSMiklos Szeredi fuse_put_request(fc, req); 36351eb01e7SMiklos Szeredi out_put_forget_req: 36451eb01e7SMiklos Szeredi fuse_put_request(fc, forget_req); 365fd72faacSMiklos Szeredi return err; 366fd72faacSMiklos Szeredi } 367fd72faacSMiklos Szeredi 3686f9f1180SMiklos Szeredi /* 3696f9f1180SMiklos Szeredi * Code shared between mknod, mkdir, symlink and link 3706f9f1180SMiklos Szeredi */ 3719e6268dbSMiklos Szeredi static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, 3729e6268dbSMiklos Szeredi struct inode *dir, struct dentry *entry, 3739e6268dbSMiklos Szeredi int mode) 3749e6268dbSMiklos Szeredi { 3759e6268dbSMiklos Szeredi struct fuse_entry_out outarg; 3769e6268dbSMiklos Szeredi struct inode *inode; 3779e6268dbSMiklos Szeredi int err; 3789e6268dbSMiklos Szeredi 3799e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 3809e6268dbSMiklos Szeredi req->out.numargs = 1; 3819e6268dbSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 3829e6268dbSMiklos Szeredi req->out.args[0].value = &outarg; 3839e6268dbSMiklos Szeredi request_send(fc, req); 3849e6268dbSMiklos Szeredi err = req->out.h.error; 3859e6268dbSMiklos Szeredi if (err) { 3869e6268dbSMiklos Szeredi fuse_put_request(fc, req); 3879e6268dbSMiklos Szeredi return err; 3889e6268dbSMiklos Szeredi } 38939ee059aSMiklos Szeredi err = -EIO; 39039ee059aSMiklos Szeredi if (invalid_nodeid(outarg.nodeid)) 39139ee059aSMiklos Szeredi goto out_put_request; 39239ee059aSMiklos Szeredi 39339ee059aSMiklos Szeredi if ((outarg.attr.mode ^ mode) & S_IFMT) 39439ee059aSMiklos Szeredi goto out_put_request; 39539ee059aSMiklos Szeredi 3969e6268dbSMiklos Szeredi inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 3979e6268dbSMiklos Szeredi &outarg.attr); 3989e6268dbSMiklos Szeredi if (!inode) { 3999e6268dbSMiklos Szeredi fuse_send_forget(fc, req, outarg.nodeid, 1); 4009e6268dbSMiklos Szeredi return -ENOMEM; 4019e6268dbSMiklos Szeredi } 4029e6268dbSMiklos Szeredi fuse_put_request(fc, req); 4039e6268dbSMiklos Szeredi 40439ee059aSMiklos Szeredi if (dir_alias(inode)) { 4059e6268dbSMiklos Szeredi iput(inode); 4069e6268dbSMiklos Szeredi return -EIO; 4079e6268dbSMiklos Szeredi } 4089e6268dbSMiklos Szeredi 4099e6268dbSMiklos Szeredi d_instantiate(entry, inode); 4100aa7c699SMiklos Szeredi fuse_change_timeout(entry, &outarg); 4119e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 4129e6268dbSMiklos Szeredi return 0; 41339ee059aSMiklos Szeredi 41439ee059aSMiklos Szeredi out_put_request: 41539ee059aSMiklos Szeredi fuse_put_request(fc, req); 41639ee059aSMiklos Szeredi return err; 4179e6268dbSMiklos Szeredi } 4189e6268dbSMiklos Szeredi 4199e6268dbSMiklos Szeredi static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, 4209e6268dbSMiklos Szeredi dev_t rdev) 4219e6268dbSMiklos Szeredi { 4229e6268dbSMiklos Szeredi struct fuse_mknod_in inarg; 4239e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 424ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 425ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 426ce1d5a49SMiklos Szeredi return PTR_ERR(req); 4279e6268dbSMiklos Szeredi 4289e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 4299e6268dbSMiklos Szeredi inarg.mode = mode; 4309e6268dbSMiklos Szeredi inarg.rdev = new_encode_dev(rdev); 4319e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_MKNOD; 4329e6268dbSMiklos Szeredi req->in.numargs = 2; 4339e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 4349e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 4359e6268dbSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 4369e6268dbSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 4379e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, mode); 4389e6268dbSMiklos Szeredi } 4399e6268dbSMiklos Szeredi 4409e6268dbSMiklos Szeredi static int fuse_create(struct inode *dir, struct dentry *entry, int mode, 4419e6268dbSMiklos Szeredi struct nameidata *nd) 4429e6268dbSMiklos Szeredi { 443fd72faacSMiklos Szeredi if (nd && (nd->flags & LOOKUP_CREATE)) { 444fd72faacSMiklos Szeredi int err = fuse_create_open(dir, entry, mode, nd); 445fd72faacSMiklos Szeredi if (err != -ENOSYS) 446fd72faacSMiklos Szeredi return err; 447fd72faacSMiklos Szeredi /* Fall back on mknod */ 448fd72faacSMiklos Szeredi } 4499e6268dbSMiklos Szeredi return fuse_mknod(dir, entry, mode, 0); 4509e6268dbSMiklos Szeredi } 4519e6268dbSMiklos Szeredi 4529e6268dbSMiklos Szeredi static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode) 4539e6268dbSMiklos Szeredi { 4549e6268dbSMiklos Szeredi struct fuse_mkdir_in inarg; 4559e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 456ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 457ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 458ce1d5a49SMiklos Szeredi return PTR_ERR(req); 4599e6268dbSMiklos Szeredi 4609e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 4619e6268dbSMiklos Szeredi inarg.mode = mode; 4629e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_MKDIR; 4639e6268dbSMiklos Szeredi req->in.numargs = 2; 4649e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 4659e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 4669e6268dbSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 4679e6268dbSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 4689e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, S_IFDIR); 4699e6268dbSMiklos Szeredi } 4709e6268dbSMiklos Szeredi 4719e6268dbSMiklos Szeredi static int fuse_symlink(struct inode *dir, struct dentry *entry, 4729e6268dbSMiklos Szeredi const char *link) 4739e6268dbSMiklos Szeredi { 4749e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 4759e6268dbSMiklos Szeredi unsigned len = strlen(link) + 1; 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 req->in.h.opcode = FUSE_SYMLINK; 4819e6268dbSMiklos Szeredi req->in.numargs = 2; 4829e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 4839e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 4849e6268dbSMiklos Szeredi req->in.args[1].size = len; 4859e6268dbSMiklos Szeredi req->in.args[1].value = link; 4869e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, S_IFLNK); 4879e6268dbSMiklos Szeredi } 4889e6268dbSMiklos Szeredi 4899e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry) 4909e6268dbSMiklos Szeredi { 4919e6268dbSMiklos Szeredi int err; 4929e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 493ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 494ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 495ce1d5a49SMiklos Szeredi return PTR_ERR(req); 4969e6268dbSMiklos Szeredi 4979e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_UNLINK; 4989e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 4999e6268dbSMiklos Szeredi req->in.numargs = 1; 5009e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 5019e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 5029e6268dbSMiklos Szeredi request_send(fc, req); 5039e6268dbSMiklos Szeredi err = req->out.h.error; 5049e6268dbSMiklos Szeredi fuse_put_request(fc, req); 5059e6268dbSMiklos Szeredi if (!err) { 5069e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 5079e6268dbSMiklos Szeredi 5089e6268dbSMiklos Szeredi /* Set nlink to zero so the inode can be cleared, if 5099e6268dbSMiklos Szeredi the inode does have more links this will be 5109e6268dbSMiklos Szeredi discovered at the next lookup/getattr */ 511*ce71ec36SDave Hansen clear_nlink(inode); 5129e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 5139e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 5148cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 5159e6268dbSMiklos Szeredi } else if (err == -EINTR) 5169e6268dbSMiklos Szeredi fuse_invalidate_entry(entry); 5179e6268dbSMiklos Szeredi return err; 5189e6268dbSMiklos Szeredi } 5199e6268dbSMiklos Szeredi 5209e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry) 5219e6268dbSMiklos Szeredi { 5229e6268dbSMiklos Szeredi int err; 5239e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 524ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 525ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 526ce1d5a49SMiklos Szeredi return PTR_ERR(req); 5279e6268dbSMiklos Szeredi 5289e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_RMDIR; 5299e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 5309e6268dbSMiklos Szeredi req->in.numargs = 1; 5319e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 5329e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 5339e6268dbSMiklos Szeredi request_send(fc, req); 5349e6268dbSMiklos Szeredi err = req->out.h.error; 5359e6268dbSMiklos Szeredi fuse_put_request(fc, req); 5369e6268dbSMiklos Szeredi if (!err) { 537*ce71ec36SDave Hansen clear_nlink(entry->d_inode); 5389e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 5398cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 5409e6268dbSMiklos Szeredi } else if (err == -EINTR) 5419e6268dbSMiklos Szeredi fuse_invalidate_entry(entry); 5429e6268dbSMiklos Szeredi return err; 5439e6268dbSMiklos Szeredi } 5449e6268dbSMiklos Szeredi 5459e6268dbSMiklos Szeredi static int fuse_rename(struct inode *olddir, struct dentry *oldent, 5469e6268dbSMiklos Szeredi struct inode *newdir, struct dentry *newent) 5479e6268dbSMiklos Szeredi { 5489e6268dbSMiklos Szeredi int err; 5499e6268dbSMiklos Szeredi struct fuse_rename_in inarg; 5509e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(olddir); 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.newdir = get_node_id(newdir); 5579e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_RENAME; 5589e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(olddir); 5599e6268dbSMiklos Szeredi req->in.numargs = 3; 5609e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 5619e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 5629e6268dbSMiklos Szeredi req->in.args[1].size = oldent->d_name.len + 1; 5639e6268dbSMiklos Szeredi req->in.args[1].value = oldent->d_name.name; 5649e6268dbSMiklos Szeredi req->in.args[2].size = newent->d_name.len + 1; 5659e6268dbSMiklos Szeredi req->in.args[2].value = newent->d_name.name; 5669e6268dbSMiklos Szeredi request_send(fc, req); 5679e6268dbSMiklos Szeredi err = req->out.h.error; 5689e6268dbSMiklos Szeredi fuse_put_request(fc, req); 5699e6268dbSMiklos Szeredi if (!err) { 5709e6268dbSMiklos Szeredi fuse_invalidate_attr(olddir); 5719e6268dbSMiklos Szeredi if (olddir != newdir) 5729e6268dbSMiklos Szeredi fuse_invalidate_attr(newdir); 5738cbdf1e6SMiklos Szeredi 5748cbdf1e6SMiklos Szeredi /* newent will end up negative */ 5758cbdf1e6SMiklos Szeredi if (newent->d_inode) 5768cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(newent); 5779e6268dbSMiklos Szeredi } else if (err == -EINTR) { 5789e6268dbSMiklos Szeredi /* If request was interrupted, DEITY only knows if the 5799e6268dbSMiklos Szeredi rename actually took place. If the invalidation 5809e6268dbSMiklos Szeredi fails (e.g. some process has CWD under the renamed 5819e6268dbSMiklos Szeredi directory), then there can be inconsistency between 5829e6268dbSMiklos Szeredi the dcache and the real filesystem. Tough luck. */ 5839e6268dbSMiklos Szeredi fuse_invalidate_entry(oldent); 5849e6268dbSMiklos Szeredi if (newent->d_inode) 5859e6268dbSMiklos Szeredi fuse_invalidate_entry(newent); 5869e6268dbSMiklos Szeredi } 5879e6268dbSMiklos Szeredi 5889e6268dbSMiklos Szeredi return err; 5899e6268dbSMiklos Szeredi } 5909e6268dbSMiklos Szeredi 5919e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir, 5929e6268dbSMiklos Szeredi struct dentry *newent) 5939e6268dbSMiklos Szeredi { 5949e6268dbSMiklos Szeredi int err; 5959e6268dbSMiklos Szeredi struct fuse_link_in inarg; 5969e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 5979e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 598ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 599ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 600ce1d5a49SMiklos Szeredi return PTR_ERR(req); 6019e6268dbSMiklos Szeredi 6029e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 6039e6268dbSMiklos Szeredi inarg.oldnodeid = get_node_id(inode); 6049e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_LINK; 6059e6268dbSMiklos Szeredi req->in.numargs = 2; 6069e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 6079e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 6089e6268dbSMiklos Szeredi req->in.args[1].size = newent->d_name.len + 1; 6099e6268dbSMiklos Szeredi req->in.args[1].value = newent->d_name.name; 6109e6268dbSMiklos Szeredi err = create_new_entry(fc, req, newdir, newent, inode->i_mode); 6119e6268dbSMiklos Szeredi /* Contrary to "normal" filesystems it can happen that link 6129e6268dbSMiklos Szeredi makes two "logical" inodes point to the same "physical" 6139e6268dbSMiklos Szeredi inode. We invalidate the attributes of the old one, so it 6149e6268dbSMiklos Szeredi will reflect changes in the backing inode (link count, 6159e6268dbSMiklos Szeredi etc.) 6169e6268dbSMiklos Szeredi */ 6179e6268dbSMiklos Szeredi if (!err || err == -EINTR) 6189e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 6199e6268dbSMiklos Szeredi return err; 6209e6268dbSMiklos Szeredi } 6219e6268dbSMiklos Szeredi 622e5e5558eSMiklos Szeredi int fuse_do_getattr(struct inode *inode) 623e5e5558eSMiklos Szeredi { 624e5e5558eSMiklos Szeredi int err; 625e5e5558eSMiklos Szeredi struct fuse_attr_out arg; 626e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 627ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 628ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 629ce1d5a49SMiklos Szeredi return PTR_ERR(req); 630e5e5558eSMiklos Szeredi 631e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_GETATTR; 632e5e5558eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 633e5e5558eSMiklos Szeredi req->out.numargs = 1; 634e5e5558eSMiklos Szeredi req->out.args[0].size = sizeof(arg); 635e5e5558eSMiklos Szeredi req->out.args[0].value = &arg; 636e5e5558eSMiklos Szeredi request_send(fc, req); 637e5e5558eSMiklos Szeredi err = req->out.h.error; 638e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 639e5e5558eSMiklos Szeredi if (!err) { 640e5e5558eSMiklos Szeredi if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) { 641e5e5558eSMiklos Szeredi make_bad_inode(inode); 642e5e5558eSMiklos Szeredi err = -EIO; 643e5e5558eSMiklos Szeredi } else { 644e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 645e5e5558eSMiklos Szeredi fuse_change_attributes(inode, &arg.attr); 646e5e5558eSMiklos Szeredi fi->i_time = time_to_jiffies(arg.attr_valid, 647e5e5558eSMiklos Szeredi arg.attr_valid_nsec); 648e5e5558eSMiklos Szeredi } 649e5e5558eSMiklos Szeredi } 650e5e5558eSMiklos Szeredi return err; 651e5e5558eSMiklos Szeredi } 652e5e5558eSMiklos Szeredi 65387729a55SMiklos Szeredi /* 65487729a55SMiklos Szeredi * Calling into a user-controlled filesystem gives the filesystem 65587729a55SMiklos Szeredi * daemon ptrace-like capabilities over the requester process. This 65687729a55SMiklos Szeredi * means, that the filesystem daemon is able to record the exact 65787729a55SMiklos Szeredi * filesystem operations performed, and can also control the behavior 65887729a55SMiklos Szeredi * of the requester process in otherwise impossible ways. For example 65987729a55SMiklos Szeredi * it can delay the operation for arbitrary length of time allowing 66087729a55SMiklos Szeredi * DoS against the requester. 66187729a55SMiklos Szeredi * 66287729a55SMiklos Szeredi * For this reason only those processes can call into the filesystem, 66387729a55SMiklos Szeredi * for which the owner of the mount has ptrace privilege. This 66487729a55SMiklos Szeredi * excludes processes started by other users, suid or sgid processes. 66587729a55SMiklos Szeredi */ 66687729a55SMiklos Szeredi static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task) 66787729a55SMiklos Szeredi { 66887729a55SMiklos Szeredi if (fc->flags & FUSE_ALLOW_OTHER) 66987729a55SMiklos Szeredi return 1; 67087729a55SMiklos Szeredi 67187729a55SMiklos Szeredi if (task->euid == fc->user_id && 67287729a55SMiklos Szeredi task->suid == fc->user_id && 67387729a55SMiklos Szeredi task->uid == fc->user_id && 67487729a55SMiklos Szeredi task->egid == fc->group_id && 67587729a55SMiklos Szeredi task->sgid == fc->group_id && 67687729a55SMiklos Szeredi task->gid == fc->group_id) 67787729a55SMiklos Szeredi return 1; 67887729a55SMiklos Szeredi 67987729a55SMiklos Szeredi return 0; 68087729a55SMiklos Szeredi } 68187729a55SMiklos Szeredi 6826f9f1180SMiklos Szeredi /* 6836f9f1180SMiklos Szeredi * Check whether the inode attributes are still valid 6846f9f1180SMiklos Szeredi * 6856f9f1180SMiklos Szeredi * If the attribute validity timeout has expired, then fetch the fresh 6866f9f1180SMiklos Szeredi * attributes with a 'getattr' request 6876f9f1180SMiklos Szeredi * 6886f9f1180SMiklos Szeredi * I'm not sure why cached attributes are never returned for the root 6896f9f1180SMiklos Szeredi * inode, this is probably being too cautious. 6906f9f1180SMiklos Szeredi */ 691e5e5558eSMiklos Szeredi static int fuse_revalidate(struct dentry *entry) 692e5e5558eSMiklos Szeredi { 693e5e5558eSMiklos Szeredi struct inode *inode = entry->d_inode; 694e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 695e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 696e5e5558eSMiklos Szeredi 69787729a55SMiklos Szeredi if (!fuse_allow_task(fc, current)) 698e5e5558eSMiklos Szeredi return -EACCES; 69987729a55SMiklos Szeredi if (get_node_id(inode) != FUSE_ROOT_ID && 7000a0898cfSMiklos Szeredi fi->i_time >= get_jiffies_64()) 701e5e5558eSMiklos Szeredi return 0; 702e5e5558eSMiklos Szeredi 703e5e5558eSMiklos Szeredi return fuse_do_getattr(inode); 704e5e5558eSMiklos Szeredi } 705e5e5558eSMiklos Szeredi 70631d40d74SMiklos Szeredi static int fuse_access(struct inode *inode, int mask) 70731d40d74SMiklos Szeredi { 70831d40d74SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 70931d40d74SMiklos Szeredi struct fuse_req *req; 71031d40d74SMiklos Szeredi struct fuse_access_in inarg; 71131d40d74SMiklos Szeredi int err; 71231d40d74SMiklos Szeredi 71331d40d74SMiklos Szeredi if (fc->no_access) 71431d40d74SMiklos Szeredi return 0; 71531d40d74SMiklos Szeredi 716ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 717ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 718ce1d5a49SMiklos Szeredi return PTR_ERR(req); 71931d40d74SMiklos Szeredi 72031d40d74SMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 72131d40d74SMiklos Szeredi inarg.mask = mask; 72231d40d74SMiklos Szeredi req->in.h.opcode = FUSE_ACCESS; 72331d40d74SMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 72431d40d74SMiklos Szeredi req->in.numargs = 1; 72531d40d74SMiklos Szeredi req->in.args[0].size = sizeof(inarg); 72631d40d74SMiklos Szeredi req->in.args[0].value = &inarg; 72731d40d74SMiklos Szeredi request_send(fc, req); 72831d40d74SMiklos Szeredi err = req->out.h.error; 72931d40d74SMiklos Szeredi fuse_put_request(fc, req); 73031d40d74SMiklos Szeredi if (err == -ENOSYS) { 73131d40d74SMiklos Szeredi fc->no_access = 1; 73231d40d74SMiklos Szeredi err = 0; 73331d40d74SMiklos Szeredi } 73431d40d74SMiklos Szeredi return err; 73531d40d74SMiklos Szeredi } 73631d40d74SMiklos Szeredi 7376f9f1180SMiklos Szeredi /* 7386f9f1180SMiklos Szeredi * Check permission. The two basic access models of FUSE are: 7396f9f1180SMiklos Szeredi * 7406f9f1180SMiklos Szeredi * 1) Local access checking ('default_permissions' mount option) based 7416f9f1180SMiklos Szeredi * on file mode. This is the plain old disk filesystem permission 7426f9f1180SMiklos Szeredi * modell. 7436f9f1180SMiklos Szeredi * 7446f9f1180SMiklos Szeredi * 2) "Remote" access checking, where server is responsible for 7456f9f1180SMiklos Szeredi * checking permission in each inode operation. An exception to this 7466f9f1180SMiklos Szeredi * is if ->permission() was invoked from sys_access() in which case an 7476f9f1180SMiklos Szeredi * access request is sent. Execute permission is still checked 7486f9f1180SMiklos Szeredi * locally based on file mode. 7496f9f1180SMiklos Szeredi */ 750e5e5558eSMiklos Szeredi static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) 751e5e5558eSMiklos Szeredi { 752e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 753e5e5558eSMiklos Szeredi 75487729a55SMiklos Szeredi if (!fuse_allow_task(fc, current)) 755e5e5558eSMiklos Szeredi return -EACCES; 7561e9a4ed9SMiklos Szeredi else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 7571e9a4ed9SMiklos Szeredi int err = generic_permission(inode, mask, NULL); 7581e9a4ed9SMiklos Szeredi 7591e9a4ed9SMiklos Szeredi /* If permission is denied, try to refresh file 7601e9a4ed9SMiklos Szeredi attributes. This is also needed, because the root 7611e9a4ed9SMiklos Szeredi node will at first have no permissions */ 7621e9a4ed9SMiklos Szeredi if (err == -EACCES) { 7631e9a4ed9SMiklos Szeredi err = fuse_do_getattr(inode); 7641e9a4ed9SMiklos Szeredi if (!err) 7651e9a4ed9SMiklos Szeredi err = generic_permission(inode, mask, NULL); 7661e9a4ed9SMiklos Szeredi } 7671e9a4ed9SMiklos Szeredi 7686f9f1180SMiklos Szeredi /* Note: the opposite of the above test does not 7696f9f1180SMiklos Szeredi exist. So if permissions are revoked this won't be 7706f9f1180SMiklos Szeredi noticed immediately, only after the attribute 7716f9f1180SMiklos Szeredi timeout has expired */ 7721e9a4ed9SMiklos Szeredi 7731e9a4ed9SMiklos Szeredi return err; 7741e9a4ed9SMiklos Szeredi } else { 775e5e5558eSMiklos Szeredi int mode = inode->i_mode; 776e5e5558eSMiklos Szeredi if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) 777e5e5558eSMiklos Szeredi return -EACCES; 77831d40d74SMiklos Szeredi 779650a8983SMiklos Szeredi if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR))) 78031d40d74SMiklos Szeredi return fuse_access(inode, mask); 781e5e5558eSMiklos Szeredi return 0; 782e5e5558eSMiklos Szeredi } 783e5e5558eSMiklos Szeredi } 784e5e5558eSMiklos Szeredi 785e5e5558eSMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file, 786e5e5558eSMiklos Szeredi void *dstbuf, filldir_t filldir) 787e5e5558eSMiklos Szeredi { 788e5e5558eSMiklos Szeredi while (nbytes >= FUSE_NAME_OFFSET) { 789e5e5558eSMiklos Szeredi struct fuse_dirent *dirent = (struct fuse_dirent *) buf; 790e5e5558eSMiklos Szeredi size_t reclen = FUSE_DIRENT_SIZE(dirent); 791e5e5558eSMiklos Szeredi int over; 792e5e5558eSMiklos Szeredi if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) 793e5e5558eSMiklos Szeredi return -EIO; 794e5e5558eSMiklos Szeredi if (reclen > nbytes) 795e5e5558eSMiklos Szeredi break; 796e5e5558eSMiklos Szeredi 797e5e5558eSMiklos Szeredi over = filldir(dstbuf, dirent->name, dirent->namelen, 798e5e5558eSMiklos Szeredi file->f_pos, dirent->ino, dirent->type); 799e5e5558eSMiklos Szeredi if (over) 800e5e5558eSMiklos Szeredi break; 801e5e5558eSMiklos Szeredi 802e5e5558eSMiklos Szeredi buf += reclen; 803e5e5558eSMiklos Szeredi nbytes -= reclen; 804e5e5558eSMiklos Szeredi file->f_pos = dirent->off; 805e5e5558eSMiklos Szeredi } 806e5e5558eSMiklos Szeredi 807e5e5558eSMiklos Szeredi return 0; 808e5e5558eSMiklos Szeredi } 809e5e5558eSMiklos Szeredi 810e5e5558eSMiklos Szeredi static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) 811e5e5558eSMiklos Szeredi { 81204730fefSMiklos Szeredi int err; 81304730fefSMiklos Szeredi size_t nbytes; 81404730fefSMiklos Szeredi struct page *page; 81504730fefSMiklos Szeredi struct inode *inode = file->f_dentry->d_inode; 81604730fefSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 817248d86e8SMiklos Szeredi struct fuse_req *req; 818248d86e8SMiklos Szeredi 819248d86e8SMiklos Szeredi if (is_bad_inode(inode)) 820248d86e8SMiklos Szeredi return -EIO; 821248d86e8SMiklos Szeredi 822ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 823ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 824ce1d5a49SMiklos Szeredi return PTR_ERR(req); 825e5e5558eSMiklos Szeredi 82604730fefSMiklos Szeredi page = alloc_page(GFP_KERNEL); 82704730fefSMiklos Szeredi if (!page) { 82804730fefSMiklos Szeredi fuse_put_request(fc, req); 829e5e5558eSMiklos Szeredi return -ENOMEM; 83004730fefSMiklos Szeredi } 83104730fefSMiklos Szeredi req->num_pages = 1; 83204730fefSMiklos Szeredi req->pages[0] = page; 833361b1eb5SMiklos Szeredi fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR); 834361b1eb5SMiklos Szeredi request_send(fc, req); 835361b1eb5SMiklos Szeredi nbytes = req->out.args[0].size; 83604730fefSMiklos Szeredi err = req->out.h.error; 83704730fefSMiklos Szeredi fuse_put_request(fc, req); 83804730fefSMiklos Szeredi if (!err) 83904730fefSMiklos Szeredi err = parse_dirfile(page_address(page), nbytes, file, dstbuf, 84004730fefSMiklos Szeredi filldir); 841e5e5558eSMiklos Szeredi 84204730fefSMiklos Szeredi __free_page(page); 843b36c31baSMiklos Szeredi fuse_invalidate_attr(inode); /* atime changed */ 84404730fefSMiklos Szeredi return err; 845e5e5558eSMiklos Szeredi } 846e5e5558eSMiklos Szeredi 847e5e5558eSMiklos Szeredi static char *read_link(struct dentry *dentry) 848e5e5558eSMiklos Szeredi { 849e5e5558eSMiklos Szeredi struct inode *inode = dentry->d_inode; 850e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 851ce1d5a49SMiklos Szeredi struct fuse_req *req = fuse_get_req(fc); 852e5e5558eSMiklos Szeredi char *link; 853e5e5558eSMiklos Szeredi 854ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 855ce1d5a49SMiklos Szeredi return ERR_PTR(PTR_ERR(req)); 856e5e5558eSMiklos Szeredi 857e5e5558eSMiklos Szeredi link = (char *) __get_free_page(GFP_KERNEL); 858e5e5558eSMiklos Szeredi if (!link) { 859e5e5558eSMiklos Szeredi link = ERR_PTR(-ENOMEM); 860e5e5558eSMiklos Szeredi goto out; 861e5e5558eSMiklos Szeredi } 862e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_READLINK; 863e5e5558eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 864e5e5558eSMiklos Szeredi req->out.argvar = 1; 865e5e5558eSMiklos Szeredi req->out.numargs = 1; 866e5e5558eSMiklos Szeredi req->out.args[0].size = PAGE_SIZE - 1; 867e5e5558eSMiklos Szeredi req->out.args[0].value = link; 868e5e5558eSMiklos Szeredi request_send(fc, req); 869e5e5558eSMiklos Szeredi if (req->out.h.error) { 870e5e5558eSMiklos Szeredi free_page((unsigned long) link); 871e5e5558eSMiklos Szeredi link = ERR_PTR(req->out.h.error); 872e5e5558eSMiklos Szeredi } else 873e5e5558eSMiklos Szeredi link[req->out.args[0].size] = '\0'; 874e5e5558eSMiklos Szeredi out: 875e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 876b36c31baSMiklos Szeredi fuse_invalidate_attr(inode); /* atime changed */ 877e5e5558eSMiklos Szeredi return link; 878e5e5558eSMiklos Szeredi } 879e5e5558eSMiklos Szeredi 880e5e5558eSMiklos Szeredi static void free_link(char *link) 881e5e5558eSMiklos Szeredi { 882e5e5558eSMiklos Szeredi if (!IS_ERR(link)) 883e5e5558eSMiklos Szeredi free_page((unsigned long) link); 884e5e5558eSMiklos Szeredi } 885e5e5558eSMiklos Szeredi 886e5e5558eSMiklos Szeredi static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd) 887e5e5558eSMiklos Szeredi { 888e5e5558eSMiklos Szeredi nd_set_link(nd, read_link(dentry)); 889e5e5558eSMiklos Szeredi return NULL; 890e5e5558eSMiklos Szeredi } 891e5e5558eSMiklos Szeredi 892e5e5558eSMiklos Szeredi static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c) 893e5e5558eSMiklos Szeredi { 894e5e5558eSMiklos Szeredi free_link(nd_get_link(nd)); 895e5e5558eSMiklos Szeredi } 896e5e5558eSMiklos Szeredi 897e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file) 898e5e5558eSMiklos Szeredi { 89904730fefSMiklos Szeredi return fuse_open_common(inode, file, 1); 900e5e5558eSMiklos Szeredi } 901e5e5558eSMiklos Szeredi 902e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file) 903e5e5558eSMiklos Szeredi { 90404730fefSMiklos Szeredi return fuse_release_common(inode, file, 1); 905e5e5558eSMiklos Szeredi } 906e5e5558eSMiklos Szeredi 90782547981SMiklos Szeredi static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync) 90882547981SMiklos Szeredi { 90982547981SMiklos Szeredi /* nfsd can call this with no file */ 91082547981SMiklos Szeredi return file ? fuse_fsync_common(file, de, datasync, 1) : 0; 91182547981SMiklos Szeredi } 91282547981SMiklos Szeredi 913befc649cSMiklos Szeredi static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) 9149e6268dbSMiklos Szeredi { 9159e6268dbSMiklos Szeredi unsigned ivalid = iattr->ia_valid; 9169e6268dbSMiklos Szeredi 9179e6268dbSMiklos Szeredi if (ivalid & ATTR_MODE) 918befc649cSMiklos Szeredi arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode; 9199e6268dbSMiklos Szeredi if (ivalid & ATTR_UID) 920befc649cSMiklos Szeredi arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid; 9219e6268dbSMiklos Szeredi if (ivalid & ATTR_GID) 922befc649cSMiklos Szeredi arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid; 9239e6268dbSMiklos Szeredi if (ivalid & ATTR_SIZE) 924befc649cSMiklos Szeredi arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size; 9259e6268dbSMiklos Szeredi /* You can only _set_ these together (they may change by themselves) */ 9269e6268dbSMiklos Szeredi if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) { 927befc649cSMiklos Szeredi arg->valid |= FATTR_ATIME | FATTR_MTIME; 928befc649cSMiklos Szeredi arg->atime = iattr->ia_atime.tv_sec; 929befc649cSMiklos Szeredi arg->mtime = iattr->ia_mtime.tv_sec; 9309e6268dbSMiklos Szeredi } 931befc649cSMiklos Szeredi if (ivalid & ATTR_FILE) { 932befc649cSMiklos Szeredi struct fuse_file *ff = iattr->ia_file->private_data; 933befc649cSMiklos Szeredi arg->valid |= FATTR_FH; 934befc649cSMiklos Szeredi arg->fh = ff->fh; 935befc649cSMiklos Szeredi } 9369e6268dbSMiklos Szeredi } 9379e6268dbSMiklos Szeredi 9386f9f1180SMiklos Szeredi /* 9396f9f1180SMiklos Szeredi * Set attributes, and at the same time refresh them. 9406f9f1180SMiklos Szeredi * 9416f9f1180SMiklos Szeredi * Truncation is slightly complicated, because the 'truncate' request 9426f9f1180SMiklos Szeredi * may fail, in which case we don't want to touch the mapping. 9436f9f1180SMiklos Szeredi * vmtruncate() doesn't allow for this case. So do the rlimit 9446f9f1180SMiklos Szeredi * checking by hand and call vmtruncate() only after the file has 9456f9f1180SMiklos Szeredi * actually been truncated. 9466f9f1180SMiklos Szeredi */ 9479e6268dbSMiklos Szeredi static int fuse_setattr(struct dentry *entry, struct iattr *attr) 9489e6268dbSMiklos Szeredi { 9499e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 9509e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 9519e6268dbSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 9529e6268dbSMiklos Szeredi struct fuse_req *req; 9539e6268dbSMiklos Szeredi struct fuse_setattr_in inarg; 9549e6268dbSMiklos Szeredi struct fuse_attr_out outarg; 9559e6268dbSMiklos Szeredi int err; 9569e6268dbSMiklos Szeredi int is_truncate = 0; 9579e6268dbSMiklos Szeredi 9581e9a4ed9SMiklos Szeredi if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 9591e9a4ed9SMiklos Szeredi err = inode_change_ok(inode, attr); 9601e9a4ed9SMiklos Szeredi if (err) 9611e9a4ed9SMiklos Szeredi return err; 9621e9a4ed9SMiklos Szeredi } 9631e9a4ed9SMiklos Szeredi 9649e6268dbSMiklos Szeredi if (attr->ia_valid & ATTR_SIZE) { 9659e6268dbSMiklos Szeredi unsigned long limit; 9669e6268dbSMiklos Szeredi is_truncate = 1; 9679e6268dbSMiklos Szeredi limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; 9689e6268dbSMiklos Szeredi if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) { 9699e6268dbSMiklos Szeredi send_sig(SIGXFSZ, current, 0); 9709e6268dbSMiklos Szeredi return -EFBIG; 9719e6268dbSMiklos Szeredi } 9729e6268dbSMiklos Szeredi } 9739e6268dbSMiklos Szeredi 974ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 975ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 976ce1d5a49SMiklos Szeredi return PTR_ERR(req); 9779e6268dbSMiklos Szeredi 9789e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 979befc649cSMiklos Szeredi iattr_to_fattr(attr, &inarg); 9809e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_SETATTR; 9819e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 9829e6268dbSMiklos Szeredi req->in.numargs = 1; 9839e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 9849e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 9859e6268dbSMiklos Szeredi req->out.numargs = 1; 9869e6268dbSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 9879e6268dbSMiklos Szeredi req->out.args[0].value = &outarg; 9889e6268dbSMiklos Szeredi request_send(fc, req); 9899e6268dbSMiklos Szeredi err = req->out.h.error; 9909e6268dbSMiklos Szeredi fuse_put_request(fc, req); 9919e6268dbSMiklos Szeredi if (!err) { 9929e6268dbSMiklos Szeredi if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { 9939e6268dbSMiklos Szeredi make_bad_inode(inode); 9949e6268dbSMiklos Szeredi err = -EIO; 9959e6268dbSMiklos Szeredi } else { 9969e6268dbSMiklos Szeredi if (is_truncate) { 9979e6268dbSMiklos Szeredi loff_t origsize = i_size_read(inode); 9989e6268dbSMiklos Szeredi i_size_write(inode, outarg.attr.size); 9999e6268dbSMiklos Szeredi if (origsize > outarg.attr.size) 10009e6268dbSMiklos Szeredi vmtruncate(inode, outarg.attr.size); 10019e6268dbSMiklos Szeredi } 10029e6268dbSMiklos Szeredi fuse_change_attributes(inode, &outarg.attr); 10039e6268dbSMiklos Szeredi fi->i_time = time_to_jiffies(outarg.attr_valid, 10049e6268dbSMiklos Szeredi outarg.attr_valid_nsec); 10059e6268dbSMiklos Szeredi } 10069e6268dbSMiklos Szeredi } else if (err == -EINTR) 10079e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 10089e6268dbSMiklos Szeredi 10099e6268dbSMiklos Szeredi return err; 10109e6268dbSMiklos Szeredi } 10119e6268dbSMiklos Szeredi 1012e5e5558eSMiklos Szeredi static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, 1013e5e5558eSMiklos Szeredi struct kstat *stat) 1014e5e5558eSMiklos Szeredi { 1015e5e5558eSMiklos Szeredi struct inode *inode = entry->d_inode; 1016e5e5558eSMiklos Szeredi int err = fuse_revalidate(entry); 1017e5e5558eSMiklos Szeredi if (!err) 1018e5e5558eSMiklos Szeredi generic_fillattr(inode, stat); 1019e5e5558eSMiklos Szeredi 1020e5e5558eSMiklos Szeredi return err; 1021e5e5558eSMiklos Szeredi } 1022e5e5558eSMiklos Szeredi 102392a8780eSMiklos Szeredi static int fuse_setxattr(struct dentry *entry, const char *name, 102492a8780eSMiklos Szeredi const void *value, size_t size, int flags) 102592a8780eSMiklos Szeredi { 102692a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 102792a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 102892a8780eSMiklos Szeredi struct fuse_req *req; 102992a8780eSMiklos Szeredi struct fuse_setxattr_in inarg; 103092a8780eSMiklos Szeredi int err; 103192a8780eSMiklos Szeredi 103292a8780eSMiklos Szeredi if (fc->no_setxattr) 103392a8780eSMiklos Szeredi return -EOPNOTSUPP; 103492a8780eSMiklos Szeredi 1035ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1036ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1037ce1d5a49SMiklos Szeredi return PTR_ERR(req); 103892a8780eSMiklos Szeredi 103992a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 104092a8780eSMiklos Szeredi inarg.size = size; 104192a8780eSMiklos Szeredi inarg.flags = flags; 104292a8780eSMiklos Szeredi req->in.h.opcode = FUSE_SETXATTR; 104392a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 104492a8780eSMiklos Szeredi req->in.numargs = 3; 104592a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 104692a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 104792a8780eSMiklos Szeredi req->in.args[1].size = strlen(name) + 1; 104892a8780eSMiklos Szeredi req->in.args[1].value = name; 104992a8780eSMiklos Szeredi req->in.args[2].size = size; 105092a8780eSMiklos Szeredi req->in.args[2].value = value; 105192a8780eSMiklos Szeredi request_send(fc, req); 105292a8780eSMiklos Szeredi err = req->out.h.error; 105392a8780eSMiklos Szeredi fuse_put_request(fc, req); 105492a8780eSMiklos Szeredi if (err == -ENOSYS) { 105592a8780eSMiklos Szeredi fc->no_setxattr = 1; 105692a8780eSMiklos Szeredi err = -EOPNOTSUPP; 105792a8780eSMiklos Szeredi } 105892a8780eSMiklos Szeredi return err; 105992a8780eSMiklos Szeredi } 106092a8780eSMiklos Szeredi 106192a8780eSMiklos Szeredi static ssize_t fuse_getxattr(struct dentry *entry, const char *name, 106292a8780eSMiklos Szeredi void *value, size_t size) 106392a8780eSMiklos Szeredi { 106492a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 106592a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 106692a8780eSMiklos Szeredi struct fuse_req *req; 106792a8780eSMiklos Szeredi struct fuse_getxattr_in inarg; 106892a8780eSMiklos Szeredi struct fuse_getxattr_out outarg; 106992a8780eSMiklos Szeredi ssize_t ret; 107092a8780eSMiklos Szeredi 107192a8780eSMiklos Szeredi if (fc->no_getxattr) 107292a8780eSMiklos Szeredi return -EOPNOTSUPP; 107392a8780eSMiklos Szeredi 1074ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1075ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1076ce1d5a49SMiklos Szeredi return PTR_ERR(req); 107792a8780eSMiklos Szeredi 107892a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 107992a8780eSMiklos Szeredi inarg.size = size; 108092a8780eSMiklos Szeredi req->in.h.opcode = FUSE_GETXATTR; 108192a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 108292a8780eSMiklos Szeredi req->in.numargs = 2; 108392a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 108492a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 108592a8780eSMiklos Szeredi req->in.args[1].size = strlen(name) + 1; 108692a8780eSMiklos Szeredi req->in.args[1].value = name; 108792a8780eSMiklos Szeredi /* This is really two different operations rolled into one */ 108892a8780eSMiklos Szeredi req->out.numargs = 1; 108992a8780eSMiklos Szeredi if (size) { 109092a8780eSMiklos Szeredi req->out.argvar = 1; 109192a8780eSMiklos Szeredi req->out.args[0].size = size; 109292a8780eSMiklos Szeredi req->out.args[0].value = value; 109392a8780eSMiklos Szeredi } else { 109492a8780eSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 109592a8780eSMiklos Szeredi req->out.args[0].value = &outarg; 109692a8780eSMiklos Szeredi } 109792a8780eSMiklos Szeredi request_send(fc, req); 109892a8780eSMiklos Szeredi ret = req->out.h.error; 109992a8780eSMiklos Szeredi if (!ret) 110092a8780eSMiklos Szeredi ret = size ? req->out.args[0].size : outarg.size; 110192a8780eSMiklos Szeredi else { 110292a8780eSMiklos Szeredi if (ret == -ENOSYS) { 110392a8780eSMiklos Szeredi fc->no_getxattr = 1; 110492a8780eSMiklos Szeredi ret = -EOPNOTSUPP; 110592a8780eSMiklos Szeredi } 110692a8780eSMiklos Szeredi } 110792a8780eSMiklos Szeredi fuse_put_request(fc, req); 110892a8780eSMiklos Szeredi return ret; 110992a8780eSMiklos Szeredi } 111092a8780eSMiklos Szeredi 111192a8780eSMiklos Szeredi static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) 111292a8780eSMiklos Szeredi { 111392a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 111492a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 111592a8780eSMiklos Szeredi struct fuse_req *req; 111692a8780eSMiklos Szeredi struct fuse_getxattr_in inarg; 111792a8780eSMiklos Szeredi struct fuse_getxattr_out outarg; 111892a8780eSMiklos Szeredi ssize_t ret; 111992a8780eSMiklos Szeredi 112092a8780eSMiklos Szeredi if (fc->no_listxattr) 112192a8780eSMiklos Szeredi return -EOPNOTSUPP; 112292a8780eSMiklos Szeredi 1123ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1124ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1125ce1d5a49SMiklos Szeredi return PTR_ERR(req); 112692a8780eSMiklos Szeredi 112792a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 112892a8780eSMiklos Szeredi inarg.size = size; 112992a8780eSMiklos Szeredi req->in.h.opcode = FUSE_LISTXATTR; 113092a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 113192a8780eSMiklos Szeredi req->in.numargs = 1; 113292a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 113392a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 113492a8780eSMiklos Szeredi /* This is really two different operations rolled into one */ 113592a8780eSMiklos Szeredi req->out.numargs = 1; 113692a8780eSMiklos Szeredi if (size) { 113792a8780eSMiklos Szeredi req->out.argvar = 1; 113892a8780eSMiklos Szeredi req->out.args[0].size = size; 113992a8780eSMiklos Szeredi req->out.args[0].value = list; 114092a8780eSMiklos Szeredi } else { 114192a8780eSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 114292a8780eSMiklos Szeredi req->out.args[0].value = &outarg; 114392a8780eSMiklos Szeredi } 114492a8780eSMiklos Szeredi request_send(fc, req); 114592a8780eSMiklos Szeredi ret = req->out.h.error; 114692a8780eSMiklos Szeredi if (!ret) 114792a8780eSMiklos Szeredi ret = size ? req->out.args[0].size : outarg.size; 114892a8780eSMiklos Szeredi else { 114992a8780eSMiklos Szeredi if (ret == -ENOSYS) { 115092a8780eSMiklos Szeredi fc->no_listxattr = 1; 115192a8780eSMiklos Szeredi ret = -EOPNOTSUPP; 115292a8780eSMiklos Szeredi } 115392a8780eSMiklos Szeredi } 115492a8780eSMiklos Szeredi fuse_put_request(fc, req); 115592a8780eSMiklos Szeredi return ret; 115692a8780eSMiklos Szeredi } 115792a8780eSMiklos Szeredi 115892a8780eSMiklos Szeredi static int fuse_removexattr(struct dentry *entry, const char *name) 115992a8780eSMiklos Szeredi { 116092a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 116192a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 116292a8780eSMiklos Szeredi struct fuse_req *req; 116392a8780eSMiklos Szeredi int err; 116492a8780eSMiklos Szeredi 116592a8780eSMiklos Szeredi if (fc->no_removexattr) 116692a8780eSMiklos Szeredi return -EOPNOTSUPP; 116792a8780eSMiklos Szeredi 1168ce1d5a49SMiklos Szeredi req = fuse_get_req(fc); 1169ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1170ce1d5a49SMiklos Szeredi return PTR_ERR(req); 117192a8780eSMiklos Szeredi 117292a8780eSMiklos Szeredi req->in.h.opcode = FUSE_REMOVEXATTR; 117392a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 117492a8780eSMiklos Szeredi req->in.numargs = 1; 117592a8780eSMiklos Szeredi req->in.args[0].size = strlen(name) + 1; 117692a8780eSMiklos Szeredi req->in.args[0].value = name; 117792a8780eSMiklos Szeredi request_send(fc, req); 117892a8780eSMiklos Szeredi err = req->out.h.error; 117992a8780eSMiklos Szeredi fuse_put_request(fc, req); 118092a8780eSMiklos Szeredi if (err == -ENOSYS) { 118192a8780eSMiklos Szeredi fc->no_removexattr = 1; 118292a8780eSMiklos Szeredi err = -EOPNOTSUPP; 118392a8780eSMiklos Szeredi } 118492a8780eSMiklos Szeredi return err; 118592a8780eSMiklos Szeredi } 118692a8780eSMiklos Szeredi 1187e5e5558eSMiklos Szeredi static struct inode_operations fuse_dir_inode_operations = { 1188e5e5558eSMiklos Szeredi .lookup = fuse_lookup, 11899e6268dbSMiklos Szeredi .mkdir = fuse_mkdir, 11909e6268dbSMiklos Szeredi .symlink = fuse_symlink, 11919e6268dbSMiklos Szeredi .unlink = fuse_unlink, 11929e6268dbSMiklos Szeredi .rmdir = fuse_rmdir, 11939e6268dbSMiklos Szeredi .rename = fuse_rename, 11949e6268dbSMiklos Szeredi .link = fuse_link, 11959e6268dbSMiklos Szeredi .setattr = fuse_setattr, 11969e6268dbSMiklos Szeredi .create = fuse_create, 11979e6268dbSMiklos Szeredi .mknod = fuse_mknod, 1198e5e5558eSMiklos Szeredi .permission = fuse_permission, 1199e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 120092a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 120192a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 120292a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 120392a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 1204e5e5558eSMiklos Szeredi }; 1205e5e5558eSMiklos Szeredi 12064b6f5d20SArjan van de Ven static const struct file_operations fuse_dir_operations = { 1207b6aeadedSMiklos Szeredi .llseek = generic_file_llseek, 1208e5e5558eSMiklos Szeredi .read = generic_read_dir, 1209e5e5558eSMiklos Szeredi .readdir = fuse_readdir, 1210e5e5558eSMiklos Szeredi .open = fuse_dir_open, 1211e5e5558eSMiklos Szeredi .release = fuse_dir_release, 121282547981SMiklos Szeredi .fsync = fuse_dir_fsync, 1213e5e5558eSMiklos Szeredi }; 1214e5e5558eSMiklos Szeredi 1215e5e5558eSMiklos Szeredi static struct inode_operations fuse_common_inode_operations = { 12169e6268dbSMiklos Szeredi .setattr = fuse_setattr, 1217e5e5558eSMiklos Szeredi .permission = fuse_permission, 1218e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 121992a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 122092a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 122192a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 122292a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 1223e5e5558eSMiklos Szeredi }; 1224e5e5558eSMiklos Szeredi 1225e5e5558eSMiklos Szeredi static struct inode_operations fuse_symlink_inode_operations = { 12269e6268dbSMiklos Szeredi .setattr = fuse_setattr, 1227e5e5558eSMiklos Szeredi .follow_link = fuse_follow_link, 1228e5e5558eSMiklos Szeredi .put_link = fuse_put_link, 1229e5e5558eSMiklos Szeredi .readlink = generic_readlink, 1230e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 123192a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 123292a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 123392a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 123492a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 1235e5e5558eSMiklos Szeredi }; 1236e5e5558eSMiklos Szeredi 1237e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode) 1238e5e5558eSMiklos Szeredi { 1239e5e5558eSMiklos Szeredi inode->i_op = &fuse_common_inode_operations; 1240e5e5558eSMiklos Szeredi } 1241e5e5558eSMiklos Szeredi 1242e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode) 1243e5e5558eSMiklos Szeredi { 1244e5e5558eSMiklos Szeredi inode->i_op = &fuse_dir_inode_operations; 1245e5e5558eSMiklos Szeredi inode->i_fop = &fuse_dir_operations; 1246e5e5558eSMiklos Szeredi } 1247e5e5558eSMiklos Szeredi 1248e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode) 1249e5e5558eSMiklos Szeredi { 1250e5e5558eSMiklos Szeredi inode->i_op = &fuse_symlink_inode_operations; 1251e5e5558eSMiklos Szeredi } 1252