1e5e5558eSMiklos Szeredi /* 2e5e5558eSMiklos Szeredi FUSE: Filesystem in Userspace 3e5e5558eSMiklos Szeredi Copyright (C) 2001-2005 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 17e5e5558eSMiklos Szeredi static inline unsigned long time_to_jiffies(unsigned long sec, 18e5e5558eSMiklos Szeredi unsigned long nsec) 19e5e5558eSMiklos Szeredi { 20e5e5558eSMiklos Szeredi struct timespec ts = {sec, nsec}; 21e5e5558eSMiklos Szeredi return jiffies + timespec_to_jiffies(&ts); 22e5e5558eSMiklos Szeredi } 23e5e5558eSMiklos Szeredi 24e5e5558eSMiklos Szeredi static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, 25e5e5558eSMiklos Szeredi struct dentry *entry, 26e5e5558eSMiklos Szeredi struct fuse_entry_out *outarg) 27e5e5558eSMiklos Szeredi { 28e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_LOOKUP; 29e5e5558eSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 30e5e5558eSMiklos Szeredi req->inode = dir; 31e5e5558eSMiklos Szeredi req->in.numargs = 1; 32e5e5558eSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 33e5e5558eSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 34e5e5558eSMiklos Szeredi req->out.numargs = 1; 35e5e5558eSMiklos Szeredi req->out.args[0].size = sizeof(struct fuse_entry_out); 36e5e5558eSMiklos Szeredi req->out.args[0].value = outarg; 37e5e5558eSMiklos Szeredi } 38e5e5558eSMiklos Szeredi 39e5e5558eSMiklos Szeredi static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) 40e5e5558eSMiklos Szeredi { 41e5e5558eSMiklos Szeredi if (!entry->d_inode || is_bad_inode(entry->d_inode)) 42e5e5558eSMiklos Szeredi return 0; 43e5e5558eSMiklos Szeredi else if (time_after(jiffies, entry->d_time)) { 44e5e5558eSMiklos Szeredi int err; 45e5e5558eSMiklos Szeredi struct fuse_entry_out outarg; 46e5e5558eSMiklos Szeredi struct inode *inode = entry->d_inode; 47e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 48e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 49e5e5558eSMiklos Szeredi struct fuse_req *req = fuse_get_request_nonint(fc); 50e5e5558eSMiklos Szeredi if (!req) 51e5e5558eSMiklos Szeredi return 0; 52e5e5558eSMiklos Szeredi 53e5e5558eSMiklos Szeredi fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg); 54e5e5558eSMiklos Szeredi request_send_nonint(fc, req); 55e5e5558eSMiklos Szeredi err = req->out.h.error; 569e6268dbSMiklos Szeredi if (!err) { 579e6268dbSMiklos Szeredi if (outarg.nodeid != get_node_id(inode)) { 589e6268dbSMiklos Szeredi fuse_send_forget(fc, req, outarg.nodeid, 1); 599e6268dbSMiklos Szeredi return 0; 609e6268dbSMiklos Szeredi } 619e6268dbSMiklos Szeredi fi->nlookup ++; 629e6268dbSMiklos Szeredi } 63e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 649e6268dbSMiklos Szeredi if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) 65e5e5558eSMiklos Szeredi return 0; 66e5e5558eSMiklos Szeredi 67e5e5558eSMiklos Szeredi fuse_change_attributes(inode, &outarg.attr); 68e5e5558eSMiklos Szeredi entry->d_time = time_to_jiffies(outarg.entry_valid, 69e5e5558eSMiklos Szeredi outarg.entry_valid_nsec); 70e5e5558eSMiklos Szeredi fi->i_time = time_to_jiffies(outarg.attr_valid, 71e5e5558eSMiklos Szeredi outarg.attr_valid_nsec); 72e5e5558eSMiklos Szeredi } 73e5e5558eSMiklos Szeredi return 1; 74e5e5558eSMiklos Szeredi } 75e5e5558eSMiklos Szeredi 76e5e5558eSMiklos Szeredi static struct dentry_operations fuse_dentry_operations = { 77e5e5558eSMiklos Szeredi .d_revalidate = fuse_dentry_revalidate, 78e5e5558eSMiklos Szeredi }; 79e5e5558eSMiklos Szeredi 80e5e5558eSMiklos Szeredi static int fuse_lookup_iget(struct inode *dir, struct dentry *entry, 81e5e5558eSMiklos Szeredi struct inode **inodep) 82e5e5558eSMiklos Szeredi { 83e5e5558eSMiklos Szeredi int err; 84e5e5558eSMiklos Szeredi struct fuse_entry_out outarg; 85e5e5558eSMiklos Szeredi struct inode *inode = NULL; 86e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 87e5e5558eSMiklos Szeredi struct fuse_req *req; 88e5e5558eSMiklos Szeredi 89e5e5558eSMiklos Szeredi if (entry->d_name.len > FUSE_NAME_MAX) 90e5e5558eSMiklos Szeredi return -ENAMETOOLONG; 91e5e5558eSMiklos Szeredi 92e5e5558eSMiklos Szeredi req = fuse_get_request(fc); 93e5e5558eSMiklos Szeredi if (!req) 94e5e5558eSMiklos Szeredi return -ERESTARTNOINTR; 95e5e5558eSMiklos Szeredi 96e5e5558eSMiklos Szeredi fuse_lookup_init(req, dir, entry, &outarg); 97e5e5558eSMiklos Szeredi request_send(fc, req); 98e5e5558eSMiklos Szeredi err = req->out.h.error; 99e5e5558eSMiklos Szeredi if (!err) { 100e5e5558eSMiklos Szeredi inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 1019e6268dbSMiklos Szeredi &outarg.attr); 102e5e5558eSMiklos Szeredi if (!inode) { 1039e6268dbSMiklos Szeredi fuse_send_forget(fc, req, outarg.nodeid, 1); 104e5e5558eSMiklos Szeredi return -ENOMEM; 105e5e5558eSMiklos Szeredi } 106e5e5558eSMiklos Szeredi } 107e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 108e5e5558eSMiklos Szeredi if (err && err != -ENOENT) 109e5e5558eSMiklos Szeredi return err; 110e5e5558eSMiklos Szeredi 111e5e5558eSMiklos Szeredi if (inode) { 112e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 113e5e5558eSMiklos Szeredi entry->d_time = time_to_jiffies(outarg.entry_valid, 114e5e5558eSMiklos Szeredi outarg.entry_valid_nsec); 115e5e5558eSMiklos Szeredi fi->i_time = time_to_jiffies(outarg.attr_valid, 116e5e5558eSMiklos Szeredi outarg.attr_valid_nsec); 117e5e5558eSMiklos Szeredi } 118e5e5558eSMiklos Szeredi 119e5e5558eSMiklos Szeredi entry->d_op = &fuse_dentry_operations; 120e5e5558eSMiklos Szeredi *inodep = inode; 121e5e5558eSMiklos Szeredi return 0; 122e5e5558eSMiklos Szeredi } 123e5e5558eSMiklos Szeredi 1249e6268dbSMiklos Szeredi void fuse_invalidate_attr(struct inode *inode) 1259e6268dbSMiklos Szeredi { 1269e6268dbSMiklos Szeredi get_fuse_inode(inode)->i_time = jiffies - 1; 1279e6268dbSMiklos Szeredi } 1289e6268dbSMiklos Szeredi 1299e6268dbSMiklos Szeredi static void fuse_invalidate_entry(struct dentry *entry) 1309e6268dbSMiklos Szeredi { 1319e6268dbSMiklos Szeredi d_invalidate(entry); 1329e6268dbSMiklos Szeredi entry->d_time = jiffies - 1; 1339e6268dbSMiklos Szeredi } 1349e6268dbSMiklos Szeredi 1359e6268dbSMiklos Szeredi static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, 1369e6268dbSMiklos Szeredi struct inode *dir, struct dentry *entry, 1379e6268dbSMiklos Szeredi int mode) 1389e6268dbSMiklos Szeredi { 1399e6268dbSMiklos Szeredi struct fuse_entry_out outarg; 1409e6268dbSMiklos Szeredi struct inode *inode; 1419e6268dbSMiklos Szeredi struct fuse_inode *fi; 1429e6268dbSMiklos Szeredi int err; 1439e6268dbSMiklos Szeredi 1449e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 1459e6268dbSMiklos Szeredi req->inode = dir; 1469e6268dbSMiklos Szeredi req->out.numargs = 1; 1479e6268dbSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 1489e6268dbSMiklos Szeredi req->out.args[0].value = &outarg; 1499e6268dbSMiklos Szeredi request_send(fc, req); 1509e6268dbSMiklos Szeredi err = req->out.h.error; 1519e6268dbSMiklos Szeredi if (err) { 1529e6268dbSMiklos Szeredi fuse_put_request(fc, req); 1539e6268dbSMiklos Szeredi return err; 1549e6268dbSMiklos Szeredi } 1559e6268dbSMiklos Szeredi inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 1569e6268dbSMiklos Szeredi &outarg.attr); 1579e6268dbSMiklos Szeredi if (!inode) { 1589e6268dbSMiklos Szeredi fuse_send_forget(fc, req, outarg.nodeid, 1); 1599e6268dbSMiklos Szeredi return -ENOMEM; 1609e6268dbSMiklos Szeredi } 1619e6268dbSMiklos Szeredi fuse_put_request(fc, req); 1629e6268dbSMiklos Szeredi 1639e6268dbSMiklos Szeredi /* Don't allow userspace to do really stupid things... */ 1649e6268dbSMiklos Szeredi if ((inode->i_mode ^ mode) & S_IFMT) { 1659e6268dbSMiklos Szeredi iput(inode); 1669e6268dbSMiklos Szeredi return -EIO; 1679e6268dbSMiklos Szeredi } 1689e6268dbSMiklos Szeredi 1699e6268dbSMiklos Szeredi entry->d_time = time_to_jiffies(outarg.entry_valid, 1709e6268dbSMiklos Szeredi outarg.entry_valid_nsec); 1719e6268dbSMiklos Szeredi 1729e6268dbSMiklos Szeredi fi = get_fuse_inode(inode); 1739e6268dbSMiklos Szeredi fi->i_time = time_to_jiffies(outarg.attr_valid, 1749e6268dbSMiklos Szeredi outarg.attr_valid_nsec); 1759e6268dbSMiklos Szeredi 1769e6268dbSMiklos Szeredi d_instantiate(entry, inode); 1779e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 1789e6268dbSMiklos Szeredi return 0; 1799e6268dbSMiklos Szeredi } 1809e6268dbSMiklos Szeredi 1819e6268dbSMiklos Szeredi static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, 1829e6268dbSMiklos Szeredi dev_t rdev) 1839e6268dbSMiklos Szeredi { 1849e6268dbSMiklos Szeredi struct fuse_mknod_in inarg; 1859e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 1869e6268dbSMiklos Szeredi struct fuse_req *req = fuse_get_request(fc); 1879e6268dbSMiklos Szeredi if (!req) 1889e6268dbSMiklos Szeredi return -ERESTARTNOINTR; 1899e6268dbSMiklos Szeredi 1909e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 1919e6268dbSMiklos Szeredi inarg.mode = mode; 1929e6268dbSMiklos Szeredi inarg.rdev = new_encode_dev(rdev); 1939e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_MKNOD; 1949e6268dbSMiklos Szeredi req->in.numargs = 2; 1959e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 1969e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 1979e6268dbSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 1989e6268dbSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 1999e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, mode); 2009e6268dbSMiklos Szeredi } 2019e6268dbSMiklos Szeredi 2029e6268dbSMiklos Szeredi static int fuse_create(struct inode *dir, struct dentry *entry, int mode, 2039e6268dbSMiklos Szeredi struct nameidata *nd) 2049e6268dbSMiklos Szeredi { 2059e6268dbSMiklos Szeredi return fuse_mknod(dir, entry, mode, 0); 2069e6268dbSMiklos Szeredi } 2079e6268dbSMiklos Szeredi 2089e6268dbSMiklos Szeredi static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode) 2099e6268dbSMiklos Szeredi { 2109e6268dbSMiklos Szeredi struct fuse_mkdir_in inarg; 2119e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 2129e6268dbSMiklos Szeredi struct fuse_req *req = fuse_get_request(fc); 2139e6268dbSMiklos Szeredi if (!req) 2149e6268dbSMiklos Szeredi return -ERESTARTNOINTR; 2159e6268dbSMiklos Szeredi 2169e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 2179e6268dbSMiklos Szeredi inarg.mode = mode; 2189e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_MKDIR; 2199e6268dbSMiklos Szeredi req->in.numargs = 2; 2209e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 2219e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 2229e6268dbSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 2239e6268dbSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 2249e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, S_IFDIR); 2259e6268dbSMiklos Szeredi } 2269e6268dbSMiklos Szeredi 2279e6268dbSMiklos Szeredi static int fuse_symlink(struct inode *dir, struct dentry *entry, 2289e6268dbSMiklos Szeredi const char *link) 2299e6268dbSMiklos Szeredi { 2309e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 2319e6268dbSMiklos Szeredi unsigned len = strlen(link) + 1; 2329e6268dbSMiklos Szeredi struct fuse_req *req; 2339e6268dbSMiklos Szeredi 2349e6268dbSMiklos Szeredi if (len > FUSE_SYMLINK_MAX) 2359e6268dbSMiklos Szeredi return -ENAMETOOLONG; 2369e6268dbSMiklos Szeredi 2379e6268dbSMiklos Szeredi req = fuse_get_request(fc); 2389e6268dbSMiklos Szeredi if (!req) 2399e6268dbSMiklos Szeredi return -ERESTARTNOINTR; 2409e6268dbSMiklos Szeredi 2419e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_SYMLINK; 2429e6268dbSMiklos Szeredi req->in.numargs = 2; 2439e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 2449e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 2459e6268dbSMiklos Szeredi req->in.args[1].size = len; 2469e6268dbSMiklos Szeredi req->in.args[1].value = link; 2479e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, S_IFLNK); 2489e6268dbSMiklos Szeredi } 2499e6268dbSMiklos Szeredi 2509e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry) 2519e6268dbSMiklos Szeredi { 2529e6268dbSMiklos Szeredi int err; 2539e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 2549e6268dbSMiklos Szeredi struct fuse_req *req = fuse_get_request(fc); 2559e6268dbSMiklos Szeredi if (!req) 2569e6268dbSMiklos Szeredi return -ERESTARTNOINTR; 2579e6268dbSMiklos Szeredi 2589e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_UNLINK; 2599e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 2609e6268dbSMiklos Szeredi req->inode = dir; 2619e6268dbSMiklos Szeredi req->in.numargs = 1; 2629e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 2639e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 2649e6268dbSMiklos Szeredi request_send(fc, req); 2659e6268dbSMiklos Szeredi err = req->out.h.error; 2669e6268dbSMiklos Szeredi fuse_put_request(fc, req); 2679e6268dbSMiklos Szeredi if (!err) { 2689e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 2699e6268dbSMiklos Szeredi 2709e6268dbSMiklos Szeredi /* Set nlink to zero so the inode can be cleared, if 2719e6268dbSMiklos Szeredi the inode does have more links this will be 2729e6268dbSMiklos Szeredi discovered at the next lookup/getattr */ 2739e6268dbSMiklos Szeredi inode->i_nlink = 0; 2749e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 2759e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 2769e6268dbSMiklos Szeredi } else if (err == -EINTR) 2779e6268dbSMiklos Szeredi fuse_invalidate_entry(entry); 2789e6268dbSMiklos Szeredi return err; 2799e6268dbSMiklos Szeredi } 2809e6268dbSMiklos Szeredi 2819e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry) 2829e6268dbSMiklos Szeredi { 2839e6268dbSMiklos Szeredi int err; 2849e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 2859e6268dbSMiklos Szeredi struct fuse_req *req = fuse_get_request(fc); 2869e6268dbSMiklos Szeredi if (!req) 2879e6268dbSMiklos Szeredi return -ERESTARTNOINTR; 2889e6268dbSMiklos Szeredi 2899e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_RMDIR; 2909e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 2919e6268dbSMiklos Szeredi req->inode = dir; 2929e6268dbSMiklos Szeredi req->in.numargs = 1; 2939e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 2949e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 2959e6268dbSMiklos Szeredi request_send(fc, req); 2969e6268dbSMiklos Szeredi err = req->out.h.error; 2979e6268dbSMiklos Szeredi fuse_put_request(fc, req); 2989e6268dbSMiklos Szeredi if (!err) { 2999e6268dbSMiklos Szeredi entry->d_inode->i_nlink = 0; 3009e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 3019e6268dbSMiklos Szeredi } else if (err == -EINTR) 3029e6268dbSMiklos Szeredi fuse_invalidate_entry(entry); 3039e6268dbSMiklos Szeredi return err; 3049e6268dbSMiklos Szeredi } 3059e6268dbSMiklos Szeredi 3069e6268dbSMiklos Szeredi static int fuse_rename(struct inode *olddir, struct dentry *oldent, 3079e6268dbSMiklos Szeredi struct inode *newdir, struct dentry *newent) 3089e6268dbSMiklos Szeredi { 3099e6268dbSMiklos Szeredi int err; 3109e6268dbSMiklos Szeredi struct fuse_rename_in inarg; 3119e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(olddir); 3129e6268dbSMiklos Szeredi struct fuse_req *req = fuse_get_request(fc); 3139e6268dbSMiklos Szeredi if (!req) 3149e6268dbSMiklos Szeredi return -ERESTARTNOINTR; 3159e6268dbSMiklos Szeredi 3169e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 3179e6268dbSMiklos Szeredi inarg.newdir = get_node_id(newdir); 3189e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_RENAME; 3199e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(olddir); 3209e6268dbSMiklos Szeredi req->inode = olddir; 3219e6268dbSMiklos Szeredi req->inode2 = newdir; 3229e6268dbSMiklos Szeredi req->in.numargs = 3; 3239e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 3249e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 3259e6268dbSMiklos Szeredi req->in.args[1].size = oldent->d_name.len + 1; 3269e6268dbSMiklos Szeredi req->in.args[1].value = oldent->d_name.name; 3279e6268dbSMiklos Szeredi req->in.args[2].size = newent->d_name.len + 1; 3289e6268dbSMiklos Szeredi req->in.args[2].value = newent->d_name.name; 3299e6268dbSMiklos Szeredi request_send(fc, req); 3309e6268dbSMiklos Szeredi err = req->out.h.error; 3319e6268dbSMiklos Szeredi fuse_put_request(fc, req); 3329e6268dbSMiklos Szeredi if (!err) { 3339e6268dbSMiklos Szeredi fuse_invalidate_attr(olddir); 3349e6268dbSMiklos Szeredi if (olddir != newdir) 3359e6268dbSMiklos Szeredi fuse_invalidate_attr(newdir); 3369e6268dbSMiklos Szeredi } else if (err == -EINTR) { 3379e6268dbSMiklos Szeredi /* If request was interrupted, DEITY only knows if the 3389e6268dbSMiklos Szeredi rename actually took place. If the invalidation 3399e6268dbSMiklos Szeredi fails (e.g. some process has CWD under the renamed 3409e6268dbSMiklos Szeredi directory), then there can be inconsistency between 3419e6268dbSMiklos Szeredi the dcache and the real filesystem. Tough luck. */ 3429e6268dbSMiklos Szeredi fuse_invalidate_entry(oldent); 3439e6268dbSMiklos Szeredi if (newent->d_inode) 3449e6268dbSMiklos Szeredi fuse_invalidate_entry(newent); 3459e6268dbSMiklos Szeredi } 3469e6268dbSMiklos Szeredi 3479e6268dbSMiklos Szeredi return err; 3489e6268dbSMiklos Szeredi } 3499e6268dbSMiklos Szeredi 3509e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir, 3519e6268dbSMiklos Szeredi struct dentry *newent) 3529e6268dbSMiklos Szeredi { 3539e6268dbSMiklos Szeredi int err; 3549e6268dbSMiklos Szeredi struct fuse_link_in inarg; 3559e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 3569e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 3579e6268dbSMiklos Szeredi struct fuse_req *req = fuse_get_request(fc); 3589e6268dbSMiklos Szeredi if (!req) 3599e6268dbSMiklos Szeredi return -ERESTARTNOINTR; 3609e6268dbSMiklos Szeredi 3619e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 3629e6268dbSMiklos Szeredi inarg.oldnodeid = get_node_id(inode); 3639e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_LINK; 3649e6268dbSMiklos Szeredi req->inode2 = inode; 3659e6268dbSMiklos Szeredi req->in.numargs = 2; 3669e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 3679e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 3689e6268dbSMiklos Szeredi req->in.args[1].size = newent->d_name.len + 1; 3699e6268dbSMiklos Szeredi req->in.args[1].value = newent->d_name.name; 3709e6268dbSMiklos Szeredi err = create_new_entry(fc, req, newdir, newent, inode->i_mode); 3719e6268dbSMiklos Szeredi /* Contrary to "normal" filesystems it can happen that link 3729e6268dbSMiklos Szeredi makes two "logical" inodes point to the same "physical" 3739e6268dbSMiklos Szeredi inode. We invalidate the attributes of the old one, so it 3749e6268dbSMiklos Szeredi will reflect changes in the backing inode (link count, 3759e6268dbSMiklos Szeredi etc.) 3769e6268dbSMiklos Szeredi */ 3779e6268dbSMiklos Szeredi if (!err || err == -EINTR) 3789e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 3799e6268dbSMiklos Szeredi return err; 3809e6268dbSMiklos Szeredi } 3819e6268dbSMiklos Szeredi 382e5e5558eSMiklos Szeredi int fuse_do_getattr(struct inode *inode) 383e5e5558eSMiklos Szeredi { 384e5e5558eSMiklos Szeredi int err; 385e5e5558eSMiklos Szeredi struct fuse_attr_out arg; 386e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 387e5e5558eSMiklos Szeredi struct fuse_req *req = fuse_get_request(fc); 388e5e5558eSMiklos Szeredi if (!req) 389e5e5558eSMiklos Szeredi return -ERESTARTNOINTR; 390e5e5558eSMiklos Szeredi 391e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_GETATTR; 392e5e5558eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 393e5e5558eSMiklos Szeredi req->inode = inode; 394e5e5558eSMiklos Szeredi req->out.numargs = 1; 395e5e5558eSMiklos Szeredi req->out.args[0].size = sizeof(arg); 396e5e5558eSMiklos Szeredi req->out.args[0].value = &arg; 397e5e5558eSMiklos Szeredi request_send(fc, req); 398e5e5558eSMiklos Szeredi err = req->out.h.error; 399e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 400e5e5558eSMiklos Szeredi if (!err) { 401e5e5558eSMiklos Szeredi if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) { 402e5e5558eSMiklos Szeredi make_bad_inode(inode); 403e5e5558eSMiklos Szeredi err = -EIO; 404e5e5558eSMiklos Szeredi } else { 405e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 406e5e5558eSMiklos Szeredi fuse_change_attributes(inode, &arg.attr); 407e5e5558eSMiklos Szeredi fi->i_time = time_to_jiffies(arg.attr_valid, 408e5e5558eSMiklos Szeredi arg.attr_valid_nsec); 409e5e5558eSMiklos Szeredi } 410e5e5558eSMiklos Szeredi } 411e5e5558eSMiklos Szeredi return err; 412e5e5558eSMiklos Szeredi } 413e5e5558eSMiklos Szeredi 41487729a55SMiklos Szeredi /* 41587729a55SMiklos Szeredi * Calling into a user-controlled filesystem gives the filesystem 41687729a55SMiklos Szeredi * daemon ptrace-like capabilities over the requester process. This 41787729a55SMiklos Szeredi * means, that the filesystem daemon is able to record the exact 41887729a55SMiklos Szeredi * filesystem operations performed, and can also control the behavior 41987729a55SMiklos Szeredi * of the requester process in otherwise impossible ways. For example 42087729a55SMiklos Szeredi * it can delay the operation for arbitrary length of time allowing 42187729a55SMiklos Szeredi * DoS against the requester. 42287729a55SMiklos Szeredi * 42387729a55SMiklos Szeredi * For this reason only those processes can call into the filesystem, 42487729a55SMiklos Szeredi * for which the owner of the mount has ptrace privilege. This 42587729a55SMiklos Szeredi * excludes processes started by other users, suid or sgid processes. 42687729a55SMiklos Szeredi */ 42787729a55SMiklos Szeredi static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task) 42887729a55SMiklos Szeredi { 42987729a55SMiklos Szeredi if (fc->flags & FUSE_ALLOW_OTHER) 43087729a55SMiklos Szeredi return 1; 43187729a55SMiklos Szeredi 43287729a55SMiklos Szeredi if (task->euid == fc->user_id && 43387729a55SMiklos Szeredi task->suid == fc->user_id && 43487729a55SMiklos Szeredi task->uid == fc->user_id && 43587729a55SMiklos Szeredi task->egid == fc->group_id && 43687729a55SMiklos Szeredi task->sgid == fc->group_id && 43787729a55SMiklos Szeredi task->gid == fc->group_id) 43887729a55SMiklos Szeredi return 1; 43987729a55SMiklos Szeredi 44087729a55SMiklos Szeredi return 0; 44187729a55SMiklos Szeredi } 44287729a55SMiklos Szeredi 443e5e5558eSMiklos Szeredi static int fuse_revalidate(struct dentry *entry) 444e5e5558eSMiklos Szeredi { 445e5e5558eSMiklos Szeredi struct inode *inode = entry->d_inode; 446e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 447e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 448e5e5558eSMiklos Szeredi 44987729a55SMiklos Szeredi if (!fuse_allow_task(fc, current)) 450e5e5558eSMiklos Szeredi return -EACCES; 45187729a55SMiklos Szeredi if (get_node_id(inode) != FUSE_ROOT_ID && 45287729a55SMiklos Szeredi time_before_eq(jiffies, fi->i_time)) 453e5e5558eSMiklos Szeredi return 0; 454e5e5558eSMiklos Szeredi 455e5e5558eSMiklos Szeredi return fuse_do_getattr(inode); 456e5e5558eSMiklos Szeredi } 457e5e5558eSMiklos Szeredi 458e5e5558eSMiklos Szeredi static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) 459e5e5558eSMiklos Szeredi { 460e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 461e5e5558eSMiklos Szeredi 46287729a55SMiklos Szeredi if (!fuse_allow_task(fc, current)) 463e5e5558eSMiklos Szeredi return -EACCES; 4641e9a4ed9SMiklos Szeredi else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 4651e9a4ed9SMiklos Szeredi int err = generic_permission(inode, mask, NULL); 4661e9a4ed9SMiklos Szeredi 4671e9a4ed9SMiklos Szeredi /* If permission is denied, try to refresh file 4681e9a4ed9SMiklos Szeredi attributes. This is also needed, because the root 4691e9a4ed9SMiklos Szeredi node will at first have no permissions */ 4701e9a4ed9SMiklos Szeredi if (err == -EACCES) { 4711e9a4ed9SMiklos Szeredi err = fuse_do_getattr(inode); 4721e9a4ed9SMiklos Szeredi if (!err) 4731e9a4ed9SMiklos Szeredi err = generic_permission(inode, mask, NULL); 4741e9a4ed9SMiklos Szeredi } 4751e9a4ed9SMiklos Szeredi 4761e9a4ed9SMiklos Szeredi /* FIXME: Need some mechanism to revoke permissions: 4771e9a4ed9SMiklos Szeredi currently if the filesystem suddenly changes the 4781e9a4ed9SMiklos Szeredi file mode, we will not be informed about it, and 4791e9a4ed9SMiklos Szeredi continue to allow access to the file/directory. 4801e9a4ed9SMiklos Szeredi 4811e9a4ed9SMiklos Szeredi This is actually not so grave, since the user can 4821e9a4ed9SMiklos Szeredi simply keep access to the file/directory anyway by 4831e9a4ed9SMiklos Szeredi keeping it open... */ 4841e9a4ed9SMiklos Szeredi 4851e9a4ed9SMiklos Szeredi return err; 4861e9a4ed9SMiklos Szeredi } else { 487e5e5558eSMiklos Szeredi int mode = inode->i_mode; 488e5e5558eSMiklos Szeredi if ((mask & MAY_WRITE) && IS_RDONLY(inode) && 489e5e5558eSMiklos Szeredi (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) 490e5e5558eSMiklos Szeredi return -EROFS; 491e5e5558eSMiklos Szeredi if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) 492e5e5558eSMiklos Szeredi return -EACCES; 493e5e5558eSMiklos Szeredi return 0; 494e5e5558eSMiklos Szeredi } 495e5e5558eSMiklos Szeredi } 496e5e5558eSMiklos Szeredi 497e5e5558eSMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file, 498e5e5558eSMiklos Szeredi void *dstbuf, filldir_t filldir) 499e5e5558eSMiklos Szeredi { 500e5e5558eSMiklos Szeredi while (nbytes >= FUSE_NAME_OFFSET) { 501e5e5558eSMiklos Szeredi struct fuse_dirent *dirent = (struct fuse_dirent *) buf; 502e5e5558eSMiklos Szeredi size_t reclen = FUSE_DIRENT_SIZE(dirent); 503e5e5558eSMiklos Szeredi int over; 504e5e5558eSMiklos Szeredi if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) 505e5e5558eSMiklos Szeredi return -EIO; 506e5e5558eSMiklos Szeredi if (reclen > nbytes) 507e5e5558eSMiklos Szeredi break; 508e5e5558eSMiklos Szeredi 509e5e5558eSMiklos Szeredi over = filldir(dstbuf, dirent->name, dirent->namelen, 510e5e5558eSMiklos Szeredi file->f_pos, dirent->ino, dirent->type); 511e5e5558eSMiklos Szeredi if (over) 512e5e5558eSMiklos Szeredi break; 513e5e5558eSMiklos Szeredi 514e5e5558eSMiklos Szeredi buf += reclen; 515e5e5558eSMiklos Szeredi nbytes -= reclen; 516e5e5558eSMiklos Szeredi file->f_pos = dirent->off; 517e5e5558eSMiklos Szeredi } 518e5e5558eSMiklos Szeredi 519e5e5558eSMiklos Szeredi return 0; 520e5e5558eSMiklos Szeredi } 521e5e5558eSMiklos Szeredi 52204730fefSMiklos Szeredi static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file, 52304730fefSMiklos Szeredi struct inode *inode, loff_t pos, 52404730fefSMiklos Szeredi size_t count) 525e5e5558eSMiklos Szeredi { 52604730fefSMiklos Szeredi return fuse_send_read_common(req, file, inode, pos, count, 1); 527e5e5558eSMiklos Szeredi } 528e5e5558eSMiklos Szeredi 529e5e5558eSMiklos Szeredi static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) 530e5e5558eSMiklos Szeredi { 53104730fefSMiklos Szeredi int err; 53204730fefSMiklos Szeredi size_t nbytes; 53304730fefSMiklos Szeredi struct page *page; 53404730fefSMiklos Szeredi struct inode *inode = file->f_dentry->d_inode; 53504730fefSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 53604730fefSMiklos Szeredi struct fuse_req *req = fuse_get_request_nonint(fc); 53704730fefSMiklos Szeredi if (!req) 53804730fefSMiklos Szeredi return -EINTR; 539e5e5558eSMiklos Szeredi 54004730fefSMiklos Szeredi page = alloc_page(GFP_KERNEL); 54104730fefSMiklos Szeredi if (!page) { 54204730fefSMiklos Szeredi fuse_put_request(fc, req); 543e5e5558eSMiklos Szeredi return -ENOMEM; 54404730fefSMiklos Szeredi } 54504730fefSMiklos Szeredi req->num_pages = 1; 54604730fefSMiklos Szeredi req->pages[0] = page; 54704730fefSMiklos Szeredi nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE); 54804730fefSMiklos Szeredi err = req->out.h.error; 54904730fefSMiklos Szeredi fuse_put_request(fc, req); 55004730fefSMiklos Szeredi if (!err) 55104730fefSMiklos Szeredi err = parse_dirfile(page_address(page), nbytes, file, dstbuf, 55204730fefSMiklos Szeredi filldir); 553e5e5558eSMiklos Szeredi 55404730fefSMiklos Szeredi __free_page(page); 555b36c31baSMiklos Szeredi fuse_invalidate_attr(inode); /* atime changed */ 55604730fefSMiklos Szeredi return err; 557e5e5558eSMiklos Szeredi } 558e5e5558eSMiklos Szeredi 559e5e5558eSMiklos Szeredi static char *read_link(struct dentry *dentry) 560e5e5558eSMiklos Szeredi { 561e5e5558eSMiklos Szeredi struct inode *inode = dentry->d_inode; 562e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 563e5e5558eSMiklos Szeredi struct fuse_req *req = fuse_get_request(fc); 564e5e5558eSMiklos Szeredi char *link; 565e5e5558eSMiklos Szeredi 566e5e5558eSMiklos Szeredi if (!req) 567e5e5558eSMiklos Szeredi return ERR_PTR(-ERESTARTNOINTR); 568e5e5558eSMiklos Szeredi 569e5e5558eSMiklos Szeredi link = (char *) __get_free_page(GFP_KERNEL); 570e5e5558eSMiklos Szeredi if (!link) { 571e5e5558eSMiklos Szeredi link = ERR_PTR(-ENOMEM); 572e5e5558eSMiklos Szeredi goto out; 573e5e5558eSMiklos Szeredi } 574e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_READLINK; 575e5e5558eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 576e5e5558eSMiklos Szeredi req->inode = inode; 577e5e5558eSMiklos Szeredi req->out.argvar = 1; 578e5e5558eSMiklos Szeredi req->out.numargs = 1; 579e5e5558eSMiklos Szeredi req->out.args[0].size = PAGE_SIZE - 1; 580e5e5558eSMiklos Szeredi req->out.args[0].value = link; 581e5e5558eSMiklos Szeredi request_send(fc, req); 582e5e5558eSMiklos Szeredi if (req->out.h.error) { 583e5e5558eSMiklos Szeredi free_page((unsigned long) link); 584e5e5558eSMiklos Szeredi link = ERR_PTR(req->out.h.error); 585e5e5558eSMiklos Szeredi } else 586e5e5558eSMiklos Szeredi link[req->out.args[0].size] = '\0'; 587e5e5558eSMiklos Szeredi out: 588e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 589b36c31baSMiklos Szeredi fuse_invalidate_attr(inode); /* atime changed */ 590e5e5558eSMiklos Szeredi return link; 591e5e5558eSMiklos Szeredi } 592e5e5558eSMiklos Szeredi 593e5e5558eSMiklos Szeredi static void free_link(char *link) 594e5e5558eSMiklos Szeredi { 595e5e5558eSMiklos Szeredi if (!IS_ERR(link)) 596e5e5558eSMiklos Szeredi free_page((unsigned long) link); 597e5e5558eSMiklos Szeredi } 598e5e5558eSMiklos Szeredi 599e5e5558eSMiklos Szeredi static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd) 600e5e5558eSMiklos Szeredi { 601e5e5558eSMiklos Szeredi nd_set_link(nd, read_link(dentry)); 602e5e5558eSMiklos Szeredi return NULL; 603e5e5558eSMiklos Szeredi } 604e5e5558eSMiklos Szeredi 605e5e5558eSMiklos Szeredi static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c) 606e5e5558eSMiklos Szeredi { 607e5e5558eSMiklos Szeredi free_link(nd_get_link(nd)); 608e5e5558eSMiklos Szeredi } 609e5e5558eSMiklos Szeredi 610e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file) 611e5e5558eSMiklos Szeredi { 61204730fefSMiklos Szeredi return fuse_open_common(inode, file, 1); 613e5e5558eSMiklos Szeredi } 614e5e5558eSMiklos Szeredi 615e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file) 616e5e5558eSMiklos Szeredi { 61704730fefSMiklos Szeredi return fuse_release_common(inode, file, 1); 618e5e5558eSMiklos Szeredi } 619e5e5558eSMiklos Szeredi 620*82547981SMiklos Szeredi static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync) 621*82547981SMiklos Szeredi { 622*82547981SMiklos Szeredi /* nfsd can call this with no file */ 623*82547981SMiklos Szeredi return file ? fuse_fsync_common(file, de, datasync, 1) : 0; 624*82547981SMiklos Szeredi } 625*82547981SMiklos Szeredi 6269e6268dbSMiklos Szeredi static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr) 6279e6268dbSMiklos Szeredi { 6289e6268dbSMiklos Szeredi unsigned ivalid = iattr->ia_valid; 6299e6268dbSMiklos Szeredi unsigned fvalid = 0; 6309e6268dbSMiklos Szeredi 6319e6268dbSMiklos Szeredi memset(fattr, 0, sizeof(*fattr)); 6329e6268dbSMiklos Szeredi 6339e6268dbSMiklos Szeredi if (ivalid & ATTR_MODE) 6349e6268dbSMiklos Szeredi fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode; 6359e6268dbSMiklos Szeredi if (ivalid & ATTR_UID) 6369e6268dbSMiklos Szeredi fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid; 6379e6268dbSMiklos Szeredi if (ivalid & ATTR_GID) 6389e6268dbSMiklos Szeredi fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid; 6399e6268dbSMiklos Szeredi if (ivalid & ATTR_SIZE) 6409e6268dbSMiklos Szeredi fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size; 6419e6268dbSMiklos Szeredi /* You can only _set_ these together (they may change by themselves) */ 6429e6268dbSMiklos Szeredi if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) { 6439e6268dbSMiklos Szeredi fvalid |= FATTR_ATIME | FATTR_MTIME; 6449e6268dbSMiklos Szeredi fattr->atime = iattr->ia_atime.tv_sec; 6459e6268dbSMiklos Szeredi fattr->mtime = iattr->ia_mtime.tv_sec; 6469e6268dbSMiklos Szeredi } 6479e6268dbSMiklos Szeredi 6489e6268dbSMiklos Szeredi return fvalid; 6499e6268dbSMiklos Szeredi } 6509e6268dbSMiklos Szeredi 6519e6268dbSMiklos Szeredi static int fuse_setattr(struct dentry *entry, struct iattr *attr) 6529e6268dbSMiklos Szeredi { 6539e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 6549e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 6559e6268dbSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 6569e6268dbSMiklos Szeredi struct fuse_req *req; 6579e6268dbSMiklos Szeredi struct fuse_setattr_in inarg; 6589e6268dbSMiklos Szeredi struct fuse_attr_out outarg; 6599e6268dbSMiklos Szeredi int err; 6609e6268dbSMiklos Szeredi int is_truncate = 0; 6619e6268dbSMiklos Szeredi 6621e9a4ed9SMiklos Szeredi if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 6631e9a4ed9SMiklos Szeredi err = inode_change_ok(inode, attr); 6641e9a4ed9SMiklos Szeredi if (err) 6651e9a4ed9SMiklos Szeredi return err; 6661e9a4ed9SMiklos Szeredi } 6671e9a4ed9SMiklos Szeredi 6689e6268dbSMiklos Szeredi if (attr->ia_valid & ATTR_SIZE) { 6699e6268dbSMiklos Szeredi unsigned long limit; 6709e6268dbSMiklos Szeredi is_truncate = 1; 6719e6268dbSMiklos Szeredi limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; 6729e6268dbSMiklos Szeredi if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) { 6739e6268dbSMiklos Szeredi send_sig(SIGXFSZ, current, 0); 6749e6268dbSMiklos Szeredi return -EFBIG; 6759e6268dbSMiklos Szeredi } 6769e6268dbSMiklos Szeredi } 6779e6268dbSMiklos Szeredi 6789e6268dbSMiklos Szeredi req = fuse_get_request(fc); 6799e6268dbSMiklos Szeredi if (!req) 6809e6268dbSMiklos Szeredi return -ERESTARTNOINTR; 6819e6268dbSMiklos Szeredi 6829e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 6839e6268dbSMiklos Szeredi inarg.valid = iattr_to_fattr(attr, &inarg.attr); 6849e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_SETATTR; 6859e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 6869e6268dbSMiklos Szeredi req->inode = inode; 6879e6268dbSMiklos Szeredi req->in.numargs = 1; 6889e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 6899e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 6909e6268dbSMiklos Szeredi req->out.numargs = 1; 6919e6268dbSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 6929e6268dbSMiklos Szeredi req->out.args[0].value = &outarg; 6939e6268dbSMiklos Szeredi request_send(fc, req); 6949e6268dbSMiklos Szeredi err = req->out.h.error; 6959e6268dbSMiklos Szeredi fuse_put_request(fc, req); 6969e6268dbSMiklos Szeredi if (!err) { 6979e6268dbSMiklos Szeredi if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { 6989e6268dbSMiklos Szeredi make_bad_inode(inode); 6999e6268dbSMiklos Szeredi err = -EIO; 7009e6268dbSMiklos Szeredi } else { 7019e6268dbSMiklos Szeredi if (is_truncate) { 7029e6268dbSMiklos Szeredi loff_t origsize = i_size_read(inode); 7039e6268dbSMiklos Szeredi i_size_write(inode, outarg.attr.size); 7049e6268dbSMiklos Szeredi if (origsize > outarg.attr.size) 7059e6268dbSMiklos Szeredi vmtruncate(inode, outarg.attr.size); 7069e6268dbSMiklos Szeredi } 7079e6268dbSMiklos Szeredi fuse_change_attributes(inode, &outarg.attr); 7089e6268dbSMiklos Szeredi fi->i_time = time_to_jiffies(outarg.attr_valid, 7099e6268dbSMiklos Szeredi outarg.attr_valid_nsec); 7109e6268dbSMiklos Szeredi } 7119e6268dbSMiklos Szeredi } else if (err == -EINTR) 7129e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 7139e6268dbSMiklos Szeredi 7149e6268dbSMiklos Szeredi return err; 7159e6268dbSMiklos Szeredi } 7169e6268dbSMiklos Szeredi 717e5e5558eSMiklos Szeredi static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, 718e5e5558eSMiklos Szeredi struct kstat *stat) 719e5e5558eSMiklos Szeredi { 720e5e5558eSMiklos Szeredi struct inode *inode = entry->d_inode; 721e5e5558eSMiklos Szeredi int err = fuse_revalidate(entry); 722e5e5558eSMiklos Szeredi if (!err) 723e5e5558eSMiklos Szeredi generic_fillattr(inode, stat); 724e5e5558eSMiklos Szeredi 725e5e5558eSMiklos Szeredi return err; 726e5e5558eSMiklos Szeredi } 727e5e5558eSMiklos Szeredi 728e5e5558eSMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, 729e5e5558eSMiklos Szeredi struct nameidata *nd) 730e5e5558eSMiklos Szeredi { 731e5e5558eSMiklos Szeredi struct inode *inode; 732e5e5558eSMiklos Szeredi int err = fuse_lookup_iget(dir, entry, &inode); 733e5e5558eSMiklos Szeredi if (err) 734e5e5558eSMiklos Szeredi return ERR_PTR(err); 735e5e5558eSMiklos Szeredi if (inode && S_ISDIR(inode->i_mode)) { 736e5e5558eSMiklos Szeredi /* Don't allow creating an alias to a directory */ 737e5e5558eSMiklos Szeredi struct dentry *alias = d_find_alias(inode); 738e5e5558eSMiklos Szeredi if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) { 739e5e5558eSMiklos Szeredi dput(alias); 740e5e5558eSMiklos Szeredi iput(inode); 741e5e5558eSMiklos Szeredi return ERR_PTR(-EIO); 742e5e5558eSMiklos Szeredi } 743e5e5558eSMiklos Szeredi } 744e5e5558eSMiklos Szeredi return d_splice_alias(inode, entry); 745e5e5558eSMiklos Szeredi } 746e5e5558eSMiklos Szeredi 74792a8780eSMiklos Szeredi static int fuse_setxattr(struct dentry *entry, const char *name, 74892a8780eSMiklos Szeredi const void *value, size_t size, int flags) 74992a8780eSMiklos Szeredi { 75092a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 75192a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 75292a8780eSMiklos Szeredi struct fuse_req *req; 75392a8780eSMiklos Szeredi struct fuse_setxattr_in inarg; 75492a8780eSMiklos Szeredi int err; 75592a8780eSMiklos Szeredi 75692a8780eSMiklos Szeredi if (size > FUSE_XATTR_SIZE_MAX) 75792a8780eSMiklos Szeredi return -E2BIG; 75892a8780eSMiklos Szeredi 75992a8780eSMiklos Szeredi if (fc->no_setxattr) 76092a8780eSMiklos Szeredi return -EOPNOTSUPP; 76192a8780eSMiklos Szeredi 76292a8780eSMiklos Szeredi req = fuse_get_request(fc); 76392a8780eSMiklos Szeredi if (!req) 76492a8780eSMiklos Szeredi return -ERESTARTNOINTR; 76592a8780eSMiklos Szeredi 76692a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 76792a8780eSMiklos Szeredi inarg.size = size; 76892a8780eSMiklos Szeredi inarg.flags = flags; 76992a8780eSMiklos Szeredi req->in.h.opcode = FUSE_SETXATTR; 77092a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 77192a8780eSMiklos Szeredi req->inode = inode; 77292a8780eSMiklos Szeredi req->in.numargs = 3; 77392a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 77492a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 77592a8780eSMiklos Szeredi req->in.args[1].size = strlen(name) + 1; 77692a8780eSMiklos Szeredi req->in.args[1].value = name; 77792a8780eSMiklos Szeredi req->in.args[2].size = size; 77892a8780eSMiklos Szeredi req->in.args[2].value = value; 77992a8780eSMiklos Szeredi request_send(fc, req); 78092a8780eSMiklos Szeredi err = req->out.h.error; 78192a8780eSMiklos Szeredi fuse_put_request(fc, req); 78292a8780eSMiklos Szeredi if (err == -ENOSYS) { 78392a8780eSMiklos Szeredi fc->no_setxattr = 1; 78492a8780eSMiklos Szeredi err = -EOPNOTSUPP; 78592a8780eSMiklos Szeredi } 78692a8780eSMiklos Szeredi return err; 78792a8780eSMiklos Szeredi } 78892a8780eSMiklos Szeredi 78992a8780eSMiklos Szeredi static ssize_t fuse_getxattr(struct dentry *entry, const char *name, 79092a8780eSMiklos Szeredi void *value, size_t size) 79192a8780eSMiklos Szeredi { 79292a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 79392a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 79492a8780eSMiklos Szeredi struct fuse_req *req; 79592a8780eSMiklos Szeredi struct fuse_getxattr_in inarg; 79692a8780eSMiklos Szeredi struct fuse_getxattr_out outarg; 79792a8780eSMiklos Szeredi ssize_t ret; 79892a8780eSMiklos Szeredi 79992a8780eSMiklos Szeredi if (fc->no_getxattr) 80092a8780eSMiklos Szeredi return -EOPNOTSUPP; 80192a8780eSMiklos Szeredi 80292a8780eSMiklos Szeredi req = fuse_get_request(fc); 80392a8780eSMiklos Szeredi if (!req) 80492a8780eSMiklos Szeredi return -ERESTARTNOINTR; 80592a8780eSMiklos Szeredi 80692a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 80792a8780eSMiklos Szeredi inarg.size = size; 80892a8780eSMiklos Szeredi req->in.h.opcode = FUSE_GETXATTR; 80992a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 81092a8780eSMiklos Szeredi req->inode = inode; 81192a8780eSMiklos Szeredi req->in.numargs = 2; 81292a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 81392a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 81492a8780eSMiklos Szeredi req->in.args[1].size = strlen(name) + 1; 81592a8780eSMiklos Szeredi req->in.args[1].value = name; 81692a8780eSMiklos Szeredi /* This is really two different operations rolled into one */ 81792a8780eSMiklos Szeredi req->out.numargs = 1; 81892a8780eSMiklos Szeredi if (size) { 81992a8780eSMiklos Szeredi req->out.argvar = 1; 82092a8780eSMiklos Szeredi req->out.args[0].size = size; 82192a8780eSMiklos Szeredi req->out.args[0].value = value; 82292a8780eSMiklos Szeredi } else { 82392a8780eSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 82492a8780eSMiklos Szeredi req->out.args[0].value = &outarg; 82592a8780eSMiklos Szeredi } 82692a8780eSMiklos Szeredi request_send(fc, req); 82792a8780eSMiklos Szeredi ret = req->out.h.error; 82892a8780eSMiklos Szeredi if (!ret) 82992a8780eSMiklos Szeredi ret = size ? req->out.args[0].size : outarg.size; 83092a8780eSMiklos Szeredi else { 83192a8780eSMiklos Szeredi if (ret == -ENOSYS) { 83292a8780eSMiklos Szeredi fc->no_getxattr = 1; 83392a8780eSMiklos Szeredi ret = -EOPNOTSUPP; 83492a8780eSMiklos Szeredi } 83592a8780eSMiklos Szeredi } 83692a8780eSMiklos Szeredi fuse_put_request(fc, req); 83792a8780eSMiklos Szeredi return ret; 83892a8780eSMiklos Szeredi } 83992a8780eSMiklos Szeredi 84092a8780eSMiklos Szeredi static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) 84192a8780eSMiklos Szeredi { 84292a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 84392a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 84492a8780eSMiklos Szeredi struct fuse_req *req; 84592a8780eSMiklos Szeredi struct fuse_getxattr_in inarg; 84692a8780eSMiklos Szeredi struct fuse_getxattr_out outarg; 84792a8780eSMiklos Szeredi ssize_t ret; 84892a8780eSMiklos Szeredi 84992a8780eSMiklos Szeredi if (fc->no_listxattr) 85092a8780eSMiklos Szeredi return -EOPNOTSUPP; 85192a8780eSMiklos Szeredi 85292a8780eSMiklos Szeredi req = fuse_get_request(fc); 85392a8780eSMiklos Szeredi if (!req) 85492a8780eSMiklos Szeredi return -ERESTARTNOINTR; 85592a8780eSMiklos Szeredi 85692a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 85792a8780eSMiklos Szeredi inarg.size = size; 85892a8780eSMiklos Szeredi req->in.h.opcode = FUSE_LISTXATTR; 85992a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 86092a8780eSMiklos Szeredi req->inode = inode; 86192a8780eSMiklos Szeredi req->in.numargs = 1; 86292a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 86392a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 86492a8780eSMiklos Szeredi /* This is really two different operations rolled into one */ 86592a8780eSMiklos Szeredi req->out.numargs = 1; 86692a8780eSMiklos Szeredi if (size) { 86792a8780eSMiklos Szeredi req->out.argvar = 1; 86892a8780eSMiklos Szeredi req->out.args[0].size = size; 86992a8780eSMiklos Szeredi req->out.args[0].value = list; 87092a8780eSMiklos Szeredi } else { 87192a8780eSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 87292a8780eSMiklos Szeredi req->out.args[0].value = &outarg; 87392a8780eSMiklos Szeredi } 87492a8780eSMiklos Szeredi request_send(fc, req); 87592a8780eSMiklos Szeredi ret = req->out.h.error; 87692a8780eSMiklos Szeredi if (!ret) 87792a8780eSMiklos Szeredi ret = size ? req->out.args[0].size : outarg.size; 87892a8780eSMiklos Szeredi else { 87992a8780eSMiklos Szeredi if (ret == -ENOSYS) { 88092a8780eSMiklos Szeredi fc->no_listxattr = 1; 88192a8780eSMiklos Szeredi ret = -EOPNOTSUPP; 88292a8780eSMiklos Szeredi } 88392a8780eSMiklos Szeredi } 88492a8780eSMiklos Szeredi fuse_put_request(fc, req); 88592a8780eSMiklos Szeredi return ret; 88692a8780eSMiklos Szeredi } 88792a8780eSMiklos Szeredi 88892a8780eSMiklos Szeredi static int fuse_removexattr(struct dentry *entry, const char *name) 88992a8780eSMiklos Szeredi { 89092a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 89192a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 89292a8780eSMiklos Szeredi struct fuse_req *req; 89392a8780eSMiklos Szeredi int err; 89492a8780eSMiklos Szeredi 89592a8780eSMiklos Szeredi if (fc->no_removexattr) 89692a8780eSMiklos Szeredi return -EOPNOTSUPP; 89792a8780eSMiklos Szeredi 89892a8780eSMiklos Szeredi req = fuse_get_request(fc); 89992a8780eSMiklos Szeredi if (!req) 90092a8780eSMiklos Szeredi return -ERESTARTNOINTR; 90192a8780eSMiklos Szeredi 90292a8780eSMiklos Szeredi req->in.h.opcode = FUSE_REMOVEXATTR; 90392a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 90492a8780eSMiklos Szeredi req->inode = inode; 90592a8780eSMiklos Szeredi req->in.numargs = 1; 90692a8780eSMiklos Szeredi req->in.args[0].size = strlen(name) + 1; 90792a8780eSMiklos Szeredi req->in.args[0].value = name; 90892a8780eSMiklos Szeredi request_send(fc, req); 90992a8780eSMiklos Szeredi err = req->out.h.error; 91092a8780eSMiklos Szeredi fuse_put_request(fc, req); 91192a8780eSMiklos Szeredi if (err == -ENOSYS) { 91292a8780eSMiklos Szeredi fc->no_removexattr = 1; 91392a8780eSMiklos Szeredi err = -EOPNOTSUPP; 91492a8780eSMiklos Szeredi } 91592a8780eSMiklos Szeredi return err; 91692a8780eSMiklos Szeredi } 91792a8780eSMiklos Szeredi 918e5e5558eSMiklos Szeredi static struct inode_operations fuse_dir_inode_operations = { 919e5e5558eSMiklos Szeredi .lookup = fuse_lookup, 9209e6268dbSMiklos Szeredi .mkdir = fuse_mkdir, 9219e6268dbSMiklos Szeredi .symlink = fuse_symlink, 9229e6268dbSMiklos Szeredi .unlink = fuse_unlink, 9239e6268dbSMiklos Szeredi .rmdir = fuse_rmdir, 9249e6268dbSMiklos Szeredi .rename = fuse_rename, 9259e6268dbSMiklos Szeredi .link = fuse_link, 9269e6268dbSMiklos Szeredi .setattr = fuse_setattr, 9279e6268dbSMiklos Szeredi .create = fuse_create, 9289e6268dbSMiklos Szeredi .mknod = fuse_mknod, 929e5e5558eSMiklos Szeredi .permission = fuse_permission, 930e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 93192a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 93292a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 93392a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 93492a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 935e5e5558eSMiklos Szeredi }; 936e5e5558eSMiklos Szeredi 937e5e5558eSMiklos Szeredi static struct file_operations fuse_dir_operations = { 938b6aeadedSMiklos Szeredi .llseek = generic_file_llseek, 939e5e5558eSMiklos Szeredi .read = generic_read_dir, 940e5e5558eSMiklos Szeredi .readdir = fuse_readdir, 941e5e5558eSMiklos Szeredi .open = fuse_dir_open, 942e5e5558eSMiklos Szeredi .release = fuse_dir_release, 943*82547981SMiklos Szeredi .fsync = fuse_dir_fsync, 944e5e5558eSMiklos Szeredi }; 945e5e5558eSMiklos Szeredi 946e5e5558eSMiklos Szeredi static struct inode_operations fuse_common_inode_operations = { 9479e6268dbSMiklos Szeredi .setattr = fuse_setattr, 948e5e5558eSMiklos Szeredi .permission = fuse_permission, 949e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 95092a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 95192a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 95292a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 95392a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 954e5e5558eSMiklos Szeredi }; 955e5e5558eSMiklos Szeredi 956e5e5558eSMiklos Szeredi static struct inode_operations fuse_symlink_inode_operations = { 9579e6268dbSMiklos Szeredi .setattr = fuse_setattr, 958e5e5558eSMiklos Szeredi .follow_link = fuse_follow_link, 959e5e5558eSMiklos Szeredi .put_link = fuse_put_link, 960e5e5558eSMiklos Szeredi .readlink = generic_readlink, 961e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 96292a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 96392a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 96492a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 96592a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 966e5e5558eSMiklos Szeredi }; 967e5e5558eSMiklos Szeredi 968e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode) 969e5e5558eSMiklos Szeredi { 970e5e5558eSMiklos Szeredi inode->i_op = &fuse_common_inode_operations; 971e5e5558eSMiklos Szeredi } 972e5e5558eSMiklos Szeredi 973e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode) 974e5e5558eSMiklos Szeredi { 975e5e5558eSMiklos Szeredi inode->i_op = &fuse_dir_inode_operations; 976e5e5558eSMiklos Szeredi inode->i_fop = &fuse_dir_operations; 977e5e5558eSMiklos Szeredi } 978e5e5558eSMiklos Szeredi 979e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode) 980e5e5558eSMiklos Szeredi { 981e5e5558eSMiklos Szeredi inode->i_op = &fuse_symlink_inode_operations; 982e5e5558eSMiklos Szeredi } 983