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); 497c352bdfSMiklos Szeredi struct fuse_req *req = fuse_get_request(fc); 50e5e5558eSMiklos Szeredi if (!req) 51e5e5558eSMiklos Szeredi return 0; 52e5e5558eSMiklos Szeredi 53e5e5558eSMiklos Szeredi fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg); 547c352bdfSMiklos Szeredi request_send(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) 947c352bdfSMiklos Szeredi return -EINTR; 95e5e5558eSMiklos Szeredi 96e5e5558eSMiklos Szeredi fuse_lookup_init(req, dir, entry, &outarg); 97e5e5558eSMiklos Szeredi request_send(fc, req); 98e5e5558eSMiklos Szeredi err = req->out.h.error; 99ee4e5271SMiklos Szeredi if (!err && (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID)) 100ee4e5271SMiklos Szeredi err = -EIO; 101e5e5558eSMiklos Szeredi if (!err) { 102e5e5558eSMiklos Szeredi inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 1039e6268dbSMiklos Szeredi &outarg.attr); 104e5e5558eSMiklos Szeredi if (!inode) { 1059e6268dbSMiklos Szeredi fuse_send_forget(fc, req, outarg.nodeid, 1); 106e5e5558eSMiklos Szeredi return -ENOMEM; 107e5e5558eSMiklos Szeredi } 108e5e5558eSMiklos Szeredi } 109e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 110e5e5558eSMiklos Szeredi if (err && err != -ENOENT) 111e5e5558eSMiklos Szeredi return err; 112e5e5558eSMiklos Szeredi 113e5e5558eSMiklos Szeredi if (inode) { 114e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 115e5e5558eSMiklos Szeredi entry->d_time = time_to_jiffies(outarg.entry_valid, 116e5e5558eSMiklos Szeredi outarg.entry_valid_nsec); 117e5e5558eSMiklos Szeredi fi->i_time = time_to_jiffies(outarg.attr_valid, 118e5e5558eSMiklos Szeredi outarg.attr_valid_nsec); 119e5e5558eSMiklos Szeredi } 120e5e5558eSMiklos Szeredi 121e5e5558eSMiklos Szeredi entry->d_op = &fuse_dentry_operations; 122e5e5558eSMiklos Szeredi *inodep = inode; 123e5e5558eSMiklos Szeredi return 0; 124e5e5558eSMiklos Szeredi } 125e5e5558eSMiklos Szeredi 1269e6268dbSMiklos Szeredi void fuse_invalidate_attr(struct inode *inode) 1279e6268dbSMiklos Szeredi { 1289e6268dbSMiklos Szeredi get_fuse_inode(inode)->i_time = jiffies - 1; 1299e6268dbSMiklos Szeredi } 1309e6268dbSMiklos Szeredi 1319e6268dbSMiklos Szeredi static void fuse_invalidate_entry(struct dentry *entry) 1329e6268dbSMiklos Szeredi { 1339e6268dbSMiklos Szeredi d_invalidate(entry); 1349e6268dbSMiklos Szeredi entry->d_time = jiffies - 1; 1359e6268dbSMiklos Szeredi } 1369e6268dbSMiklos Szeredi 1379e6268dbSMiklos Szeredi static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, 1389e6268dbSMiklos Szeredi struct inode *dir, struct dentry *entry, 1399e6268dbSMiklos Szeredi int mode) 1409e6268dbSMiklos Szeredi { 1419e6268dbSMiklos Szeredi struct fuse_entry_out outarg; 1429e6268dbSMiklos Szeredi struct inode *inode; 1439e6268dbSMiklos Szeredi struct fuse_inode *fi; 1449e6268dbSMiklos Szeredi int err; 1459e6268dbSMiklos Szeredi 1469e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 1479e6268dbSMiklos Szeredi req->inode = dir; 1489e6268dbSMiklos Szeredi req->out.numargs = 1; 1499e6268dbSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 1509e6268dbSMiklos Szeredi req->out.args[0].value = &outarg; 1519e6268dbSMiklos Szeredi request_send(fc, req); 1529e6268dbSMiklos Szeredi err = req->out.h.error; 1539e6268dbSMiklos Szeredi if (err) { 1549e6268dbSMiklos Szeredi fuse_put_request(fc, req); 1559e6268dbSMiklos Szeredi return err; 1569e6268dbSMiklos Szeredi } 157ee4e5271SMiklos Szeredi if (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID) { 158ee4e5271SMiklos Szeredi fuse_put_request(fc, req); 159ee4e5271SMiklos Szeredi return -EIO; 160ee4e5271SMiklos Szeredi } 1619e6268dbSMiklos Szeredi inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 1629e6268dbSMiklos Szeredi &outarg.attr); 1639e6268dbSMiklos Szeredi if (!inode) { 1649e6268dbSMiklos Szeredi fuse_send_forget(fc, req, outarg.nodeid, 1); 1659e6268dbSMiklos Szeredi return -ENOMEM; 1669e6268dbSMiklos Szeredi } 1679e6268dbSMiklos Szeredi fuse_put_request(fc, req); 1689e6268dbSMiklos Szeredi 1699e6268dbSMiklos Szeredi /* Don't allow userspace to do really stupid things... */ 1709e6268dbSMiklos Szeredi if ((inode->i_mode ^ mode) & S_IFMT) { 1719e6268dbSMiklos Szeredi iput(inode); 1729e6268dbSMiklos Szeredi return -EIO; 1739e6268dbSMiklos Szeredi } 1749e6268dbSMiklos Szeredi 1759e6268dbSMiklos Szeredi entry->d_time = time_to_jiffies(outarg.entry_valid, 1769e6268dbSMiklos Szeredi outarg.entry_valid_nsec); 1779e6268dbSMiklos Szeredi 1789e6268dbSMiklos Szeredi fi = get_fuse_inode(inode); 1799e6268dbSMiklos Szeredi fi->i_time = time_to_jiffies(outarg.attr_valid, 1809e6268dbSMiklos Szeredi outarg.attr_valid_nsec); 1819e6268dbSMiklos Szeredi 1829e6268dbSMiklos Szeredi d_instantiate(entry, inode); 1839e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 1849e6268dbSMiklos Szeredi return 0; 1859e6268dbSMiklos Szeredi } 1869e6268dbSMiklos Szeredi 1879e6268dbSMiklos Szeredi static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, 1889e6268dbSMiklos Szeredi dev_t rdev) 1899e6268dbSMiklos Szeredi { 1909e6268dbSMiklos Szeredi struct fuse_mknod_in inarg; 1919e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 1929e6268dbSMiklos Szeredi struct fuse_req *req = fuse_get_request(fc); 1939e6268dbSMiklos Szeredi if (!req) 1947c352bdfSMiklos Szeredi return -EINTR; 1959e6268dbSMiklos Szeredi 1969e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 1979e6268dbSMiklos Szeredi inarg.mode = mode; 1989e6268dbSMiklos Szeredi inarg.rdev = new_encode_dev(rdev); 1999e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_MKNOD; 2009e6268dbSMiklos Szeredi req->in.numargs = 2; 2019e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 2029e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 2039e6268dbSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 2049e6268dbSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 2059e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, mode); 2069e6268dbSMiklos Szeredi } 2079e6268dbSMiklos Szeredi 2089e6268dbSMiklos Szeredi static int fuse_create(struct inode *dir, struct dentry *entry, int mode, 2099e6268dbSMiklos Szeredi struct nameidata *nd) 2109e6268dbSMiklos Szeredi { 2119e6268dbSMiklos Szeredi return fuse_mknod(dir, entry, mode, 0); 2129e6268dbSMiklos Szeredi } 2139e6268dbSMiklos Szeredi 2149e6268dbSMiklos Szeredi static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode) 2159e6268dbSMiklos Szeredi { 2169e6268dbSMiklos Szeredi struct fuse_mkdir_in inarg; 2179e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 2189e6268dbSMiklos Szeredi struct fuse_req *req = fuse_get_request(fc); 2199e6268dbSMiklos Szeredi if (!req) 2207c352bdfSMiklos Szeredi return -EINTR; 2219e6268dbSMiklos Szeredi 2229e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 2239e6268dbSMiklos Szeredi inarg.mode = mode; 2249e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_MKDIR; 2259e6268dbSMiklos Szeredi req->in.numargs = 2; 2269e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 2279e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 2289e6268dbSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 2299e6268dbSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 2309e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, S_IFDIR); 2319e6268dbSMiklos Szeredi } 2329e6268dbSMiklos Szeredi 2339e6268dbSMiklos Szeredi static int fuse_symlink(struct inode *dir, struct dentry *entry, 2349e6268dbSMiklos Szeredi const char *link) 2359e6268dbSMiklos Szeredi { 2369e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 2379e6268dbSMiklos Szeredi unsigned len = strlen(link) + 1; 2389e6268dbSMiklos Szeredi struct fuse_req *req; 2399e6268dbSMiklos Szeredi 2409e6268dbSMiklos Szeredi if (len > FUSE_SYMLINK_MAX) 2419e6268dbSMiklos Szeredi return -ENAMETOOLONG; 2429e6268dbSMiklos Szeredi 2439e6268dbSMiklos Szeredi req = fuse_get_request(fc); 2449e6268dbSMiklos Szeredi if (!req) 2457c352bdfSMiklos Szeredi return -EINTR; 2469e6268dbSMiklos Szeredi 2479e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_SYMLINK; 2489e6268dbSMiklos Szeredi req->in.numargs = 2; 2499e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 2509e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 2519e6268dbSMiklos Szeredi req->in.args[1].size = len; 2529e6268dbSMiklos Szeredi req->in.args[1].value = link; 2539e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, S_IFLNK); 2549e6268dbSMiklos Szeredi } 2559e6268dbSMiklos Szeredi 2569e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry) 2579e6268dbSMiklos Szeredi { 2589e6268dbSMiklos Szeredi int err; 2599e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 2609e6268dbSMiklos Szeredi struct fuse_req *req = fuse_get_request(fc); 2619e6268dbSMiklos Szeredi if (!req) 2627c352bdfSMiklos Szeredi return -EINTR; 2639e6268dbSMiklos Szeredi 2649e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_UNLINK; 2659e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 2669e6268dbSMiklos Szeredi req->inode = dir; 2679e6268dbSMiklos Szeredi req->in.numargs = 1; 2689e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 2699e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 2709e6268dbSMiklos Szeredi request_send(fc, req); 2719e6268dbSMiklos Szeredi err = req->out.h.error; 2729e6268dbSMiklos Szeredi fuse_put_request(fc, req); 2739e6268dbSMiklos Szeredi if (!err) { 2749e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 2759e6268dbSMiklos Szeredi 2769e6268dbSMiklos Szeredi /* Set nlink to zero so the inode can be cleared, if 2779e6268dbSMiklos Szeredi the inode does have more links this will be 2789e6268dbSMiklos Szeredi discovered at the next lookup/getattr */ 2799e6268dbSMiklos Szeredi inode->i_nlink = 0; 2809e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 2819e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 2829e6268dbSMiklos Szeredi } else if (err == -EINTR) 2839e6268dbSMiklos Szeredi fuse_invalidate_entry(entry); 2849e6268dbSMiklos Szeredi return err; 2859e6268dbSMiklos Szeredi } 2869e6268dbSMiklos Szeredi 2879e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry) 2889e6268dbSMiklos Szeredi { 2899e6268dbSMiklos Szeredi int err; 2909e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 2919e6268dbSMiklos Szeredi struct fuse_req *req = fuse_get_request(fc); 2929e6268dbSMiklos Szeredi if (!req) 2937c352bdfSMiklos Szeredi return -EINTR; 2949e6268dbSMiklos Szeredi 2959e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_RMDIR; 2969e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 2979e6268dbSMiklos Szeredi req->inode = dir; 2989e6268dbSMiklos Szeredi req->in.numargs = 1; 2999e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 3009e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 3019e6268dbSMiklos Szeredi request_send(fc, req); 3029e6268dbSMiklos Szeredi err = req->out.h.error; 3039e6268dbSMiklos Szeredi fuse_put_request(fc, req); 3049e6268dbSMiklos Szeredi if (!err) { 3059e6268dbSMiklos Szeredi entry->d_inode->i_nlink = 0; 3069e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 3079e6268dbSMiklos Szeredi } else if (err == -EINTR) 3089e6268dbSMiklos Szeredi fuse_invalidate_entry(entry); 3099e6268dbSMiklos Szeredi return err; 3109e6268dbSMiklos Szeredi } 3119e6268dbSMiklos Szeredi 3129e6268dbSMiklos Szeredi static int fuse_rename(struct inode *olddir, struct dentry *oldent, 3139e6268dbSMiklos Szeredi struct inode *newdir, struct dentry *newent) 3149e6268dbSMiklos Szeredi { 3159e6268dbSMiklos Szeredi int err; 3169e6268dbSMiklos Szeredi struct fuse_rename_in inarg; 3179e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(olddir); 3189e6268dbSMiklos Szeredi struct fuse_req *req = fuse_get_request(fc); 3199e6268dbSMiklos Szeredi if (!req) 3207c352bdfSMiklos Szeredi return -EINTR; 3219e6268dbSMiklos Szeredi 3229e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 3239e6268dbSMiklos Szeredi inarg.newdir = get_node_id(newdir); 3249e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_RENAME; 3259e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(olddir); 3269e6268dbSMiklos Szeredi req->inode = olddir; 3279e6268dbSMiklos Szeredi req->inode2 = newdir; 3289e6268dbSMiklos Szeredi req->in.numargs = 3; 3299e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 3309e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 3319e6268dbSMiklos Szeredi req->in.args[1].size = oldent->d_name.len + 1; 3329e6268dbSMiklos Szeredi req->in.args[1].value = oldent->d_name.name; 3339e6268dbSMiklos Szeredi req->in.args[2].size = newent->d_name.len + 1; 3349e6268dbSMiklos Szeredi req->in.args[2].value = newent->d_name.name; 3359e6268dbSMiklos Szeredi request_send(fc, req); 3369e6268dbSMiklos Szeredi err = req->out.h.error; 3379e6268dbSMiklos Szeredi fuse_put_request(fc, req); 3389e6268dbSMiklos Szeredi if (!err) { 3399e6268dbSMiklos Szeredi fuse_invalidate_attr(olddir); 3409e6268dbSMiklos Szeredi if (olddir != newdir) 3419e6268dbSMiklos Szeredi fuse_invalidate_attr(newdir); 3429e6268dbSMiklos Szeredi } else if (err == -EINTR) { 3439e6268dbSMiklos Szeredi /* If request was interrupted, DEITY only knows if the 3449e6268dbSMiklos Szeredi rename actually took place. If the invalidation 3459e6268dbSMiklos Szeredi fails (e.g. some process has CWD under the renamed 3469e6268dbSMiklos Szeredi directory), then there can be inconsistency between 3479e6268dbSMiklos Szeredi the dcache and the real filesystem. Tough luck. */ 3489e6268dbSMiklos Szeredi fuse_invalidate_entry(oldent); 3499e6268dbSMiklos Szeredi if (newent->d_inode) 3509e6268dbSMiklos Szeredi fuse_invalidate_entry(newent); 3519e6268dbSMiklos Szeredi } 3529e6268dbSMiklos Szeredi 3539e6268dbSMiklos Szeredi return err; 3549e6268dbSMiklos Szeredi } 3559e6268dbSMiklos Szeredi 3569e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir, 3579e6268dbSMiklos Szeredi struct dentry *newent) 3589e6268dbSMiklos Szeredi { 3599e6268dbSMiklos Szeredi int err; 3609e6268dbSMiklos Szeredi struct fuse_link_in inarg; 3619e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 3629e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 3639e6268dbSMiklos Szeredi struct fuse_req *req = fuse_get_request(fc); 3649e6268dbSMiklos Szeredi if (!req) 3657c352bdfSMiklos Szeredi return -EINTR; 3669e6268dbSMiklos Szeredi 3679e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 3689e6268dbSMiklos Szeredi inarg.oldnodeid = get_node_id(inode); 3699e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_LINK; 3709e6268dbSMiklos Szeredi req->inode2 = inode; 3719e6268dbSMiklos Szeredi req->in.numargs = 2; 3729e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 3739e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 3749e6268dbSMiklos Szeredi req->in.args[1].size = newent->d_name.len + 1; 3759e6268dbSMiklos Szeredi req->in.args[1].value = newent->d_name.name; 3769e6268dbSMiklos Szeredi err = create_new_entry(fc, req, newdir, newent, inode->i_mode); 3779e6268dbSMiklos Szeredi /* Contrary to "normal" filesystems it can happen that link 3789e6268dbSMiklos Szeredi makes two "logical" inodes point to the same "physical" 3799e6268dbSMiklos Szeredi inode. We invalidate the attributes of the old one, so it 3809e6268dbSMiklos Szeredi will reflect changes in the backing inode (link count, 3819e6268dbSMiklos Szeredi etc.) 3829e6268dbSMiklos Szeredi */ 3839e6268dbSMiklos Szeredi if (!err || err == -EINTR) 3849e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 3859e6268dbSMiklos Szeredi return err; 3869e6268dbSMiklos Szeredi } 3879e6268dbSMiklos Szeredi 388e5e5558eSMiklos Szeredi int fuse_do_getattr(struct inode *inode) 389e5e5558eSMiklos Szeredi { 390e5e5558eSMiklos Szeredi int err; 391e5e5558eSMiklos Szeredi struct fuse_attr_out arg; 392e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 393e5e5558eSMiklos Szeredi struct fuse_req *req = fuse_get_request(fc); 394e5e5558eSMiklos Szeredi if (!req) 3957c352bdfSMiklos Szeredi return -EINTR; 396e5e5558eSMiklos Szeredi 397e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_GETATTR; 398e5e5558eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 399e5e5558eSMiklos Szeredi req->inode = inode; 400e5e5558eSMiklos Szeredi req->out.numargs = 1; 401e5e5558eSMiklos Szeredi req->out.args[0].size = sizeof(arg); 402e5e5558eSMiklos Szeredi req->out.args[0].value = &arg; 403e5e5558eSMiklos Szeredi request_send(fc, req); 404e5e5558eSMiklos Szeredi err = req->out.h.error; 405e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 406e5e5558eSMiklos Szeredi if (!err) { 407e5e5558eSMiklos Szeredi if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) { 408e5e5558eSMiklos Szeredi make_bad_inode(inode); 409e5e5558eSMiklos Szeredi err = -EIO; 410e5e5558eSMiklos Szeredi } else { 411e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 412e5e5558eSMiklos Szeredi fuse_change_attributes(inode, &arg.attr); 413e5e5558eSMiklos Szeredi fi->i_time = time_to_jiffies(arg.attr_valid, 414e5e5558eSMiklos Szeredi arg.attr_valid_nsec); 415e5e5558eSMiklos Szeredi } 416e5e5558eSMiklos Szeredi } 417e5e5558eSMiklos Szeredi return err; 418e5e5558eSMiklos Szeredi } 419e5e5558eSMiklos Szeredi 42087729a55SMiklos Szeredi /* 42187729a55SMiklos Szeredi * Calling into a user-controlled filesystem gives the filesystem 42287729a55SMiklos Szeredi * daemon ptrace-like capabilities over the requester process. This 42387729a55SMiklos Szeredi * means, that the filesystem daemon is able to record the exact 42487729a55SMiklos Szeredi * filesystem operations performed, and can also control the behavior 42587729a55SMiklos Szeredi * of the requester process in otherwise impossible ways. For example 42687729a55SMiklos Szeredi * it can delay the operation for arbitrary length of time allowing 42787729a55SMiklos Szeredi * DoS against the requester. 42887729a55SMiklos Szeredi * 42987729a55SMiklos Szeredi * For this reason only those processes can call into the filesystem, 43087729a55SMiklos Szeredi * for which the owner of the mount has ptrace privilege. This 43187729a55SMiklos Szeredi * excludes processes started by other users, suid or sgid processes. 43287729a55SMiklos Szeredi */ 43387729a55SMiklos Szeredi static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task) 43487729a55SMiklos Szeredi { 43587729a55SMiklos Szeredi if (fc->flags & FUSE_ALLOW_OTHER) 43687729a55SMiklos Szeredi return 1; 43787729a55SMiklos Szeredi 43887729a55SMiklos Szeredi if (task->euid == fc->user_id && 43987729a55SMiklos Szeredi task->suid == fc->user_id && 44087729a55SMiklos Szeredi task->uid == fc->user_id && 44187729a55SMiklos Szeredi task->egid == fc->group_id && 44287729a55SMiklos Szeredi task->sgid == fc->group_id && 44387729a55SMiklos Szeredi task->gid == fc->group_id) 44487729a55SMiklos Szeredi return 1; 44587729a55SMiklos Szeredi 44687729a55SMiklos Szeredi return 0; 44787729a55SMiklos Szeredi } 44887729a55SMiklos Szeredi 449e5e5558eSMiklos Szeredi static int fuse_revalidate(struct dentry *entry) 450e5e5558eSMiklos Szeredi { 451e5e5558eSMiklos Szeredi struct inode *inode = entry->d_inode; 452e5e5558eSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 453e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 454e5e5558eSMiklos Szeredi 45587729a55SMiklos Szeredi if (!fuse_allow_task(fc, current)) 456e5e5558eSMiklos Szeredi return -EACCES; 45787729a55SMiklos Szeredi if (get_node_id(inode) != FUSE_ROOT_ID && 45887729a55SMiklos Szeredi time_before_eq(jiffies, fi->i_time)) 459e5e5558eSMiklos Szeredi return 0; 460e5e5558eSMiklos Szeredi 461e5e5558eSMiklos Szeredi return fuse_do_getattr(inode); 462e5e5558eSMiklos Szeredi } 463e5e5558eSMiklos Szeredi 464e5e5558eSMiklos Szeredi static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) 465e5e5558eSMiklos Szeredi { 466e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 467e5e5558eSMiklos Szeredi 46887729a55SMiklos Szeredi if (!fuse_allow_task(fc, current)) 469e5e5558eSMiklos Szeredi return -EACCES; 4701e9a4ed9SMiklos Szeredi else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 4711e9a4ed9SMiklos Szeredi int err = generic_permission(inode, mask, NULL); 4721e9a4ed9SMiklos Szeredi 4731e9a4ed9SMiklos Szeredi /* If permission is denied, try to refresh file 4741e9a4ed9SMiklos Szeredi attributes. This is also needed, because the root 4751e9a4ed9SMiklos Szeredi node will at first have no permissions */ 4761e9a4ed9SMiklos Szeredi if (err == -EACCES) { 4771e9a4ed9SMiklos Szeredi err = fuse_do_getattr(inode); 4781e9a4ed9SMiklos Szeredi if (!err) 4791e9a4ed9SMiklos Szeredi err = generic_permission(inode, mask, NULL); 4801e9a4ed9SMiklos Szeredi } 4811e9a4ed9SMiklos Szeredi 4821e9a4ed9SMiklos Szeredi /* FIXME: Need some mechanism to revoke permissions: 4831e9a4ed9SMiklos Szeredi currently if the filesystem suddenly changes the 4841e9a4ed9SMiklos Szeredi file mode, we will not be informed about it, and 4851e9a4ed9SMiklos Szeredi continue to allow access to the file/directory. 4861e9a4ed9SMiklos Szeredi 4871e9a4ed9SMiklos Szeredi This is actually not so grave, since the user can 4881e9a4ed9SMiklos Szeredi simply keep access to the file/directory anyway by 4891e9a4ed9SMiklos Szeredi keeping it open... */ 4901e9a4ed9SMiklos Szeredi 4911e9a4ed9SMiklos Szeredi return err; 4921e9a4ed9SMiklos Szeredi } else { 493e5e5558eSMiklos Szeredi int mode = inode->i_mode; 494e5e5558eSMiklos Szeredi if ((mask & MAY_WRITE) && IS_RDONLY(inode) && 495e5e5558eSMiklos Szeredi (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) 496e5e5558eSMiklos Szeredi return -EROFS; 497e5e5558eSMiklos Szeredi if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) 498e5e5558eSMiklos Szeredi return -EACCES; 499e5e5558eSMiklos Szeredi return 0; 500e5e5558eSMiklos Szeredi } 501e5e5558eSMiklos Szeredi } 502e5e5558eSMiklos Szeredi 503e5e5558eSMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file, 504e5e5558eSMiklos Szeredi void *dstbuf, filldir_t filldir) 505e5e5558eSMiklos Szeredi { 506e5e5558eSMiklos Szeredi while (nbytes >= FUSE_NAME_OFFSET) { 507e5e5558eSMiklos Szeredi struct fuse_dirent *dirent = (struct fuse_dirent *) buf; 508e5e5558eSMiklos Szeredi size_t reclen = FUSE_DIRENT_SIZE(dirent); 509e5e5558eSMiklos Szeredi int over; 510e5e5558eSMiklos Szeredi if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) 511e5e5558eSMiklos Szeredi return -EIO; 512e5e5558eSMiklos Szeredi if (reclen > nbytes) 513e5e5558eSMiklos Szeredi break; 514e5e5558eSMiklos Szeredi 515e5e5558eSMiklos Szeredi over = filldir(dstbuf, dirent->name, dirent->namelen, 516e5e5558eSMiklos Szeredi file->f_pos, dirent->ino, dirent->type); 517e5e5558eSMiklos Szeredi if (over) 518e5e5558eSMiklos Szeredi break; 519e5e5558eSMiklos Szeredi 520e5e5558eSMiklos Szeredi buf += reclen; 521e5e5558eSMiklos Szeredi nbytes -= reclen; 522e5e5558eSMiklos Szeredi file->f_pos = dirent->off; 523e5e5558eSMiklos Szeredi } 524e5e5558eSMiklos Szeredi 525e5e5558eSMiklos Szeredi return 0; 526e5e5558eSMiklos Szeredi } 527e5e5558eSMiklos Szeredi 52804730fefSMiklos Szeredi static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file, 52904730fefSMiklos Szeredi struct inode *inode, loff_t pos, 53004730fefSMiklos Szeredi size_t count) 531e5e5558eSMiklos Szeredi { 53204730fefSMiklos Szeredi return fuse_send_read_common(req, file, inode, pos, count, 1); 533e5e5558eSMiklos Szeredi } 534e5e5558eSMiklos Szeredi 535e5e5558eSMiklos Szeredi static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) 536e5e5558eSMiklos Szeredi { 53704730fefSMiklos Szeredi int err; 53804730fefSMiklos Szeredi size_t nbytes; 53904730fefSMiklos Szeredi struct page *page; 54004730fefSMiklos Szeredi struct inode *inode = file->f_dentry->d_inode; 54104730fefSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 5427c352bdfSMiklos Szeredi struct fuse_req *req = fuse_get_request(fc); 54304730fefSMiklos Szeredi if (!req) 54404730fefSMiklos Szeredi return -EINTR; 545e5e5558eSMiklos Szeredi 54604730fefSMiklos Szeredi page = alloc_page(GFP_KERNEL); 54704730fefSMiklos Szeredi if (!page) { 54804730fefSMiklos Szeredi fuse_put_request(fc, req); 549e5e5558eSMiklos Szeredi return -ENOMEM; 55004730fefSMiklos Szeredi } 55104730fefSMiklos Szeredi req->num_pages = 1; 55204730fefSMiklos Szeredi req->pages[0] = page; 55304730fefSMiklos Szeredi nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE); 55404730fefSMiklos Szeredi err = req->out.h.error; 55504730fefSMiklos Szeredi fuse_put_request(fc, req); 55604730fefSMiklos Szeredi if (!err) 55704730fefSMiklos Szeredi err = parse_dirfile(page_address(page), nbytes, file, dstbuf, 55804730fefSMiklos Szeredi filldir); 559e5e5558eSMiklos Szeredi 56004730fefSMiklos Szeredi __free_page(page); 561b36c31baSMiklos Szeredi fuse_invalidate_attr(inode); /* atime changed */ 56204730fefSMiklos Szeredi return err; 563e5e5558eSMiklos Szeredi } 564e5e5558eSMiklos Szeredi 565e5e5558eSMiklos Szeredi static char *read_link(struct dentry *dentry) 566e5e5558eSMiklos Szeredi { 567e5e5558eSMiklos Szeredi struct inode *inode = dentry->d_inode; 568e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 569e5e5558eSMiklos Szeredi struct fuse_req *req = fuse_get_request(fc); 570e5e5558eSMiklos Szeredi char *link; 571e5e5558eSMiklos Szeredi 572e5e5558eSMiklos Szeredi if (!req) 5737c352bdfSMiklos Szeredi return ERR_PTR(-EINTR); 574e5e5558eSMiklos Szeredi 575e5e5558eSMiklos Szeredi link = (char *) __get_free_page(GFP_KERNEL); 576e5e5558eSMiklos Szeredi if (!link) { 577e5e5558eSMiklos Szeredi link = ERR_PTR(-ENOMEM); 578e5e5558eSMiklos Szeredi goto out; 579e5e5558eSMiklos Szeredi } 580e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_READLINK; 581e5e5558eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 582e5e5558eSMiklos Szeredi req->inode = inode; 583e5e5558eSMiklos Szeredi req->out.argvar = 1; 584e5e5558eSMiklos Szeredi req->out.numargs = 1; 585e5e5558eSMiklos Szeredi req->out.args[0].size = PAGE_SIZE - 1; 586e5e5558eSMiklos Szeredi req->out.args[0].value = link; 587e5e5558eSMiklos Szeredi request_send(fc, req); 588e5e5558eSMiklos Szeredi if (req->out.h.error) { 589e5e5558eSMiklos Szeredi free_page((unsigned long) link); 590e5e5558eSMiklos Szeredi link = ERR_PTR(req->out.h.error); 591e5e5558eSMiklos Szeredi } else 592e5e5558eSMiklos Szeredi link[req->out.args[0].size] = '\0'; 593e5e5558eSMiklos Szeredi out: 594e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 595b36c31baSMiklos Szeredi fuse_invalidate_attr(inode); /* atime changed */ 596e5e5558eSMiklos Szeredi return link; 597e5e5558eSMiklos Szeredi } 598e5e5558eSMiklos Szeredi 599e5e5558eSMiklos Szeredi static void free_link(char *link) 600e5e5558eSMiklos Szeredi { 601e5e5558eSMiklos Szeredi if (!IS_ERR(link)) 602e5e5558eSMiklos Szeredi free_page((unsigned long) link); 603e5e5558eSMiklos Szeredi } 604e5e5558eSMiklos Szeredi 605e5e5558eSMiklos Szeredi static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd) 606e5e5558eSMiklos Szeredi { 607e5e5558eSMiklos Szeredi nd_set_link(nd, read_link(dentry)); 608e5e5558eSMiklos Szeredi return NULL; 609e5e5558eSMiklos Szeredi } 610e5e5558eSMiklos Szeredi 611e5e5558eSMiklos Szeredi static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c) 612e5e5558eSMiklos Szeredi { 613e5e5558eSMiklos Szeredi free_link(nd_get_link(nd)); 614e5e5558eSMiklos Szeredi } 615e5e5558eSMiklos Szeredi 616e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file) 617e5e5558eSMiklos Szeredi { 61804730fefSMiklos Szeredi return fuse_open_common(inode, file, 1); 619e5e5558eSMiklos Szeredi } 620e5e5558eSMiklos Szeredi 621e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file) 622e5e5558eSMiklos Szeredi { 62304730fefSMiklos Szeredi return fuse_release_common(inode, file, 1); 624e5e5558eSMiklos Szeredi } 625e5e5558eSMiklos Szeredi 62682547981SMiklos Szeredi static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync) 62782547981SMiklos Szeredi { 62882547981SMiklos Szeredi /* nfsd can call this with no file */ 62982547981SMiklos Szeredi return file ? fuse_fsync_common(file, de, datasync, 1) : 0; 63082547981SMiklos Szeredi } 63182547981SMiklos Szeredi 6329e6268dbSMiklos Szeredi static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr) 6339e6268dbSMiklos Szeredi { 6349e6268dbSMiklos Szeredi unsigned ivalid = iattr->ia_valid; 6359e6268dbSMiklos Szeredi unsigned fvalid = 0; 6369e6268dbSMiklos Szeredi 6379e6268dbSMiklos Szeredi memset(fattr, 0, sizeof(*fattr)); 6389e6268dbSMiklos Szeredi 6399e6268dbSMiklos Szeredi if (ivalid & ATTR_MODE) 6409e6268dbSMiklos Szeredi fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode; 6419e6268dbSMiklos Szeredi if (ivalid & ATTR_UID) 6429e6268dbSMiklos Szeredi fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid; 6439e6268dbSMiklos Szeredi if (ivalid & ATTR_GID) 6449e6268dbSMiklos Szeredi fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid; 6459e6268dbSMiklos Szeredi if (ivalid & ATTR_SIZE) 6469e6268dbSMiklos Szeredi fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size; 6479e6268dbSMiklos Szeredi /* You can only _set_ these together (they may change by themselves) */ 6489e6268dbSMiklos Szeredi if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) { 6499e6268dbSMiklos Szeredi fvalid |= FATTR_ATIME | FATTR_MTIME; 6509e6268dbSMiklos Szeredi fattr->atime = iattr->ia_atime.tv_sec; 6519e6268dbSMiklos Szeredi fattr->mtime = iattr->ia_mtime.tv_sec; 6529e6268dbSMiklos Szeredi } 6539e6268dbSMiklos Szeredi 6549e6268dbSMiklos Szeredi return fvalid; 6559e6268dbSMiklos Szeredi } 6569e6268dbSMiklos Szeredi 6579e6268dbSMiklos Szeredi static int fuse_setattr(struct dentry *entry, struct iattr *attr) 6589e6268dbSMiklos Szeredi { 6599e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 6609e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 6619e6268dbSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 6629e6268dbSMiklos Szeredi struct fuse_req *req; 6639e6268dbSMiklos Szeredi struct fuse_setattr_in inarg; 6649e6268dbSMiklos Szeredi struct fuse_attr_out outarg; 6659e6268dbSMiklos Szeredi int err; 6669e6268dbSMiklos Szeredi int is_truncate = 0; 6679e6268dbSMiklos Szeredi 6681e9a4ed9SMiklos Szeredi if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 6691e9a4ed9SMiklos Szeredi err = inode_change_ok(inode, attr); 6701e9a4ed9SMiklos Szeredi if (err) 6711e9a4ed9SMiklos Szeredi return err; 6721e9a4ed9SMiklos Szeredi } 6731e9a4ed9SMiklos Szeredi 6749e6268dbSMiklos Szeredi if (attr->ia_valid & ATTR_SIZE) { 6759e6268dbSMiklos Szeredi unsigned long limit; 6769e6268dbSMiklos Szeredi is_truncate = 1; 6779e6268dbSMiklos Szeredi limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; 6789e6268dbSMiklos Szeredi if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) { 6799e6268dbSMiklos Szeredi send_sig(SIGXFSZ, current, 0); 6809e6268dbSMiklos Szeredi return -EFBIG; 6819e6268dbSMiklos Szeredi } 6829e6268dbSMiklos Szeredi } 6839e6268dbSMiklos Szeredi 6849e6268dbSMiklos Szeredi req = fuse_get_request(fc); 6859e6268dbSMiklos Szeredi if (!req) 6867c352bdfSMiklos Szeredi return -EINTR; 6879e6268dbSMiklos Szeredi 6889e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 6899e6268dbSMiklos Szeredi inarg.valid = iattr_to_fattr(attr, &inarg.attr); 6909e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_SETATTR; 6919e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 6929e6268dbSMiklos Szeredi req->inode = inode; 6939e6268dbSMiklos Szeredi req->in.numargs = 1; 6949e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 6959e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 6969e6268dbSMiklos Szeredi req->out.numargs = 1; 6979e6268dbSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 6989e6268dbSMiklos Szeredi req->out.args[0].value = &outarg; 6999e6268dbSMiklos Szeredi request_send(fc, req); 7009e6268dbSMiklos Szeredi err = req->out.h.error; 7019e6268dbSMiklos Szeredi fuse_put_request(fc, req); 7029e6268dbSMiklos Szeredi if (!err) { 7039e6268dbSMiklos Szeredi if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { 7049e6268dbSMiklos Szeredi make_bad_inode(inode); 7059e6268dbSMiklos Szeredi err = -EIO; 7069e6268dbSMiklos Szeredi } else { 7079e6268dbSMiklos Szeredi if (is_truncate) { 7089e6268dbSMiklos Szeredi loff_t origsize = i_size_read(inode); 7099e6268dbSMiklos Szeredi i_size_write(inode, outarg.attr.size); 7109e6268dbSMiklos Szeredi if (origsize > outarg.attr.size) 7119e6268dbSMiklos Szeredi vmtruncate(inode, outarg.attr.size); 7129e6268dbSMiklos Szeredi } 7139e6268dbSMiklos Szeredi fuse_change_attributes(inode, &outarg.attr); 7149e6268dbSMiklos Szeredi fi->i_time = time_to_jiffies(outarg.attr_valid, 7159e6268dbSMiklos Szeredi outarg.attr_valid_nsec); 7169e6268dbSMiklos Szeredi } 7179e6268dbSMiklos Szeredi } else if (err == -EINTR) 7189e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 7199e6268dbSMiklos Szeredi 7209e6268dbSMiklos Szeredi return err; 7219e6268dbSMiklos Szeredi } 7229e6268dbSMiklos Szeredi 723e5e5558eSMiklos Szeredi static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, 724e5e5558eSMiklos Szeredi struct kstat *stat) 725e5e5558eSMiklos Szeredi { 726e5e5558eSMiklos Szeredi struct inode *inode = entry->d_inode; 727e5e5558eSMiklos Szeredi int err = fuse_revalidate(entry); 728e5e5558eSMiklos Szeredi if (!err) 729e5e5558eSMiklos Szeredi generic_fillattr(inode, stat); 730e5e5558eSMiklos Szeredi 731e5e5558eSMiklos Szeredi return err; 732e5e5558eSMiklos Szeredi } 733e5e5558eSMiklos Szeredi 734e5e5558eSMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, 735e5e5558eSMiklos Szeredi struct nameidata *nd) 736e5e5558eSMiklos Szeredi { 737e5e5558eSMiklos Szeredi struct inode *inode; 738e5e5558eSMiklos Szeredi int err = fuse_lookup_iget(dir, entry, &inode); 739e5e5558eSMiklos Szeredi if (err) 740e5e5558eSMiklos Szeredi return ERR_PTR(err); 741e5e5558eSMiklos Szeredi if (inode && S_ISDIR(inode->i_mode)) { 742e5e5558eSMiklos Szeredi /* Don't allow creating an alias to a directory */ 743e5e5558eSMiklos Szeredi struct dentry *alias = d_find_alias(inode); 744*f12ec440SMiklos Szeredi if (alias) { 745e5e5558eSMiklos Szeredi dput(alias); 746e5e5558eSMiklos Szeredi iput(inode); 747e5e5558eSMiklos Szeredi return ERR_PTR(-EIO); 748e5e5558eSMiklos Szeredi } 749e5e5558eSMiklos Szeredi } 750*f12ec440SMiklos Szeredi d_add(entry, inode); 751*f12ec440SMiklos Szeredi return NULL; 752e5e5558eSMiklos Szeredi } 753e5e5558eSMiklos Szeredi 75492a8780eSMiklos Szeredi static int fuse_setxattr(struct dentry *entry, const char *name, 75592a8780eSMiklos Szeredi const void *value, size_t size, int flags) 75692a8780eSMiklos Szeredi { 75792a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 75892a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 75992a8780eSMiklos Szeredi struct fuse_req *req; 76092a8780eSMiklos Szeredi struct fuse_setxattr_in inarg; 76192a8780eSMiklos Szeredi int err; 76292a8780eSMiklos Szeredi 76392a8780eSMiklos Szeredi if (size > FUSE_XATTR_SIZE_MAX) 76492a8780eSMiklos Szeredi return -E2BIG; 76592a8780eSMiklos Szeredi 76692a8780eSMiklos Szeredi if (fc->no_setxattr) 76792a8780eSMiklos Szeredi return -EOPNOTSUPP; 76892a8780eSMiklos Szeredi 76992a8780eSMiklos Szeredi req = fuse_get_request(fc); 77092a8780eSMiklos Szeredi if (!req) 7717c352bdfSMiklos Szeredi return -EINTR; 77292a8780eSMiklos Szeredi 77392a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 77492a8780eSMiklos Szeredi inarg.size = size; 77592a8780eSMiklos Szeredi inarg.flags = flags; 77692a8780eSMiklos Szeredi req->in.h.opcode = FUSE_SETXATTR; 77792a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 77892a8780eSMiklos Szeredi req->inode = inode; 77992a8780eSMiklos Szeredi req->in.numargs = 3; 78092a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 78192a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 78292a8780eSMiklos Szeredi req->in.args[1].size = strlen(name) + 1; 78392a8780eSMiklos Szeredi req->in.args[1].value = name; 78492a8780eSMiklos Szeredi req->in.args[2].size = size; 78592a8780eSMiklos Szeredi req->in.args[2].value = value; 78692a8780eSMiklos Szeredi request_send(fc, req); 78792a8780eSMiklos Szeredi err = req->out.h.error; 78892a8780eSMiklos Szeredi fuse_put_request(fc, req); 78992a8780eSMiklos Szeredi if (err == -ENOSYS) { 79092a8780eSMiklos Szeredi fc->no_setxattr = 1; 79192a8780eSMiklos Szeredi err = -EOPNOTSUPP; 79292a8780eSMiklos Szeredi } 79392a8780eSMiklos Szeredi return err; 79492a8780eSMiklos Szeredi } 79592a8780eSMiklos Szeredi 79692a8780eSMiklos Szeredi static ssize_t fuse_getxattr(struct dentry *entry, const char *name, 79792a8780eSMiklos Szeredi void *value, size_t size) 79892a8780eSMiklos Szeredi { 79992a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 80092a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 80192a8780eSMiklos Szeredi struct fuse_req *req; 80292a8780eSMiklos Szeredi struct fuse_getxattr_in inarg; 80392a8780eSMiklos Szeredi struct fuse_getxattr_out outarg; 80492a8780eSMiklos Szeredi ssize_t ret; 80592a8780eSMiklos Szeredi 80692a8780eSMiklos Szeredi if (fc->no_getxattr) 80792a8780eSMiklos Szeredi return -EOPNOTSUPP; 80892a8780eSMiklos Szeredi 80992a8780eSMiklos Szeredi req = fuse_get_request(fc); 81092a8780eSMiklos Szeredi if (!req) 8117c352bdfSMiklos Szeredi return -EINTR; 81292a8780eSMiklos Szeredi 81392a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 81492a8780eSMiklos Szeredi inarg.size = size; 81592a8780eSMiklos Szeredi req->in.h.opcode = FUSE_GETXATTR; 81692a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 81792a8780eSMiklos Szeredi req->inode = inode; 81892a8780eSMiklos Szeredi req->in.numargs = 2; 81992a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 82092a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 82192a8780eSMiklos Szeredi req->in.args[1].size = strlen(name) + 1; 82292a8780eSMiklos Szeredi req->in.args[1].value = name; 82392a8780eSMiklos Szeredi /* This is really two different operations rolled into one */ 82492a8780eSMiklos Szeredi req->out.numargs = 1; 82592a8780eSMiklos Szeredi if (size) { 82692a8780eSMiklos Szeredi req->out.argvar = 1; 82792a8780eSMiklos Szeredi req->out.args[0].size = size; 82892a8780eSMiklos Szeredi req->out.args[0].value = value; 82992a8780eSMiklos Szeredi } else { 83092a8780eSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 83192a8780eSMiklos Szeredi req->out.args[0].value = &outarg; 83292a8780eSMiklos Szeredi } 83392a8780eSMiklos Szeredi request_send(fc, req); 83492a8780eSMiklos Szeredi ret = req->out.h.error; 83592a8780eSMiklos Szeredi if (!ret) 83692a8780eSMiklos Szeredi ret = size ? req->out.args[0].size : outarg.size; 83792a8780eSMiklos Szeredi else { 83892a8780eSMiklos Szeredi if (ret == -ENOSYS) { 83992a8780eSMiklos Szeredi fc->no_getxattr = 1; 84092a8780eSMiklos Szeredi ret = -EOPNOTSUPP; 84192a8780eSMiklos Szeredi } 84292a8780eSMiklos Szeredi } 84392a8780eSMiklos Szeredi fuse_put_request(fc, req); 84492a8780eSMiklos Szeredi return ret; 84592a8780eSMiklos Szeredi } 84692a8780eSMiklos Szeredi 84792a8780eSMiklos Szeredi static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) 84892a8780eSMiklos Szeredi { 84992a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 85092a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 85192a8780eSMiklos Szeredi struct fuse_req *req; 85292a8780eSMiklos Szeredi struct fuse_getxattr_in inarg; 85392a8780eSMiklos Szeredi struct fuse_getxattr_out outarg; 85492a8780eSMiklos Szeredi ssize_t ret; 85592a8780eSMiklos Szeredi 85692a8780eSMiklos Szeredi if (fc->no_listxattr) 85792a8780eSMiklos Szeredi return -EOPNOTSUPP; 85892a8780eSMiklos Szeredi 85992a8780eSMiklos Szeredi req = fuse_get_request(fc); 86092a8780eSMiklos Szeredi if (!req) 8617c352bdfSMiklos Szeredi return -EINTR; 86292a8780eSMiklos Szeredi 86392a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 86492a8780eSMiklos Szeredi inarg.size = size; 86592a8780eSMiklos Szeredi req->in.h.opcode = FUSE_LISTXATTR; 86692a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 86792a8780eSMiklos Szeredi req->inode = inode; 86892a8780eSMiklos Szeredi req->in.numargs = 1; 86992a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 87092a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 87192a8780eSMiklos Szeredi /* This is really two different operations rolled into one */ 87292a8780eSMiklos Szeredi req->out.numargs = 1; 87392a8780eSMiklos Szeredi if (size) { 87492a8780eSMiklos Szeredi req->out.argvar = 1; 87592a8780eSMiklos Szeredi req->out.args[0].size = size; 87692a8780eSMiklos Szeredi req->out.args[0].value = list; 87792a8780eSMiklos Szeredi } else { 87892a8780eSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 87992a8780eSMiklos Szeredi req->out.args[0].value = &outarg; 88092a8780eSMiklos Szeredi } 88192a8780eSMiklos Szeredi request_send(fc, req); 88292a8780eSMiklos Szeredi ret = req->out.h.error; 88392a8780eSMiklos Szeredi if (!ret) 88492a8780eSMiklos Szeredi ret = size ? req->out.args[0].size : outarg.size; 88592a8780eSMiklos Szeredi else { 88692a8780eSMiklos Szeredi if (ret == -ENOSYS) { 88792a8780eSMiklos Szeredi fc->no_listxattr = 1; 88892a8780eSMiklos Szeredi ret = -EOPNOTSUPP; 88992a8780eSMiklos Szeredi } 89092a8780eSMiklos Szeredi } 89192a8780eSMiklos Szeredi fuse_put_request(fc, req); 89292a8780eSMiklos Szeredi return ret; 89392a8780eSMiklos Szeredi } 89492a8780eSMiklos Szeredi 89592a8780eSMiklos Szeredi static int fuse_removexattr(struct dentry *entry, const char *name) 89692a8780eSMiklos Szeredi { 89792a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 89892a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 89992a8780eSMiklos Szeredi struct fuse_req *req; 90092a8780eSMiklos Szeredi int err; 90192a8780eSMiklos Szeredi 90292a8780eSMiklos Szeredi if (fc->no_removexattr) 90392a8780eSMiklos Szeredi return -EOPNOTSUPP; 90492a8780eSMiklos Szeredi 90592a8780eSMiklos Szeredi req = fuse_get_request(fc); 90692a8780eSMiklos Szeredi if (!req) 9077c352bdfSMiklos Szeredi return -EINTR; 90892a8780eSMiklos Szeredi 90992a8780eSMiklos Szeredi req->in.h.opcode = FUSE_REMOVEXATTR; 91092a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 91192a8780eSMiklos Szeredi req->inode = inode; 91292a8780eSMiklos Szeredi req->in.numargs = 1; 91392a8780eSMiklos Szeredi req->in.args[0].size = strlen(name) + 1; 91492a8780eSMiklos Szeredi req->in.args[0].value = name; 91592a8780eSMiklos Szeredi request_send(fc, req); 91692a8780eSMiklos Szeredi err = req->out.h.error; 91792a8780eSMiklos Szeredi fuse_put_request(fc, req); 91892a8780eSMiklos Szeredi if (err == -ENOSYS) { 91992a8780eSMiklos Szeredi fc->no_removexattr = 1; 92092a8780eSMiklos Szeredi err = -EOPNOTSUPP; 92192a8780eSMiklos Szeredi } 92292a8780eSMiklos Szeredi return err; 92392a8780eSMiklos Szeredi } 92492a8780eSMiklos Szeredi 925e5e5558eSMiklos Szeredi static struct inode_operations fuse_dir_inode_operations = { 926e5e5558eSMiklos Szeredi .lookup = fuse_lookup, 9279e6268dbSMiklos Szeredi .mkdir = fuse_mkdir, 9289e6268dbSMiklos Szeredi .symlink = fuse_symlink, 9299e6268dbSMiklos Szeredi .unlink = fuse_unlink, 9309e6268dbSMiklos Szeredi .rmdir = fuse_rmdir, 9319e6268dbSMiklos Szeredi .rename = fuse_rename, 9329e6268dbSMiklos Szeredi .link = fuse_link, 9339e6268dbSMiklos Szeredi .setattr = fuse_setattr, 9349e6268dbSMiklos Szeredi .create = fuse_create, 9359e6268dbSMiklos Szeredi .mknod = fuse_mknod, 936e5e5558eSMiklos Szeredi .permission = fuse_permission, 937e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 93892a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 93992a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 94092a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 94192a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 942e5e5558eSMiklos Szeredi }; 943e5e5558eSMiklos Szeredi 944e5e5558eSMiklos Szeredi static struct file_operations fuse_dir_operations = { 945b6aeadedSMiklos Szeredi .llseek = generic_file_llseek, 946e5e5558eSMiklos Szeredi .read = generic_read_dir, 947e5e5558eSMiklos Szeredi .readdir = fuse_readdir, 948e5e5558eSMiklos Szeredi .open = fuse_dir_open, 949e5e5558eSMiklos Szeredi .release = fuse_dir_release, 95082547981SMiklos Szeredi .fsync = fuse_dir_fsync, 951e5e5558eSMiklos Szeredi }; 952e5e5558eSMiklos Szeredi 953e5e5558eSMiklos Szeredi static struct inode_operations fuse_common_inode_operations = { 9549e6268dbSMiklos Szeredi .setattr = fuse_setattr, 955e5e5558eSMiklos Szeredi .permission = fuse_permission, 956e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 95792a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 95892a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 95992a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 96092a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 961e5e5558eSMiklos Szeredi }; 962e5e5558eSMiklos Szeredi 963e5e5558eSMiklos Szeredi static struct inode_operations fuse_symlink_inode_operations = { 9649e6268dbSMiklos Szeredi .setattr = fuse_setattr, 965e5e5558eSMiklos Szeredi .follow_link = fuse_follow_link, 966e5e5558eSMiklos Szeredi .put_link = fuse_put_link, 967e5e5558eSMiklos Szeredi .readlink = generic_readlink, 968e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 96992a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 97092a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 97192a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 97292a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 973e5e5558eSMiklos Szeredi }; 974e5e5558eSMiklos Szeredi 975e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode) 976e5e5558eSMiklos Szeredi { 977e5e5558eSMiklos Szeredi inode->i_op = &fuse_common_inode_operations; 978e5e5558eSMiklos Szeredi } 979e5e5558eSMiklos Szeredi 980e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode) 981e5e5558eSMiklos Szeredi { 982e5e5558eSMiklos Szeredi inode->i_op = &fuse_dir_inode_operations; 983e5e5558eSMiklos Szeredi inode->i_fop = &fuse_dir_operations; 984e5e5558eSMiklos Szeredi } 985e5e5558eSMiklos Szeredi 986e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode) 987e5e5558eSMiklos Szeredi { 988e5e5558eSMiklos Szeredi inode->i_op = &fuse_symlink_inode_operations; 989e5e5558eSMiklos Szeredi } 990