1e5e5558eSMiklos Szeredi /* 2e5e5558eSMiklos Szeredi FUSE: Filesystem in Userspace 31729a16cSMiklos Szeredi Copyright (C) 2001-2008 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/sched.h> 14e5e5558eSMiklos Szeredi #include <linux/namei.h> 1507e77dcaSMiklos Szeredi #include <linux/slab.h> 16e5e5558eSMiklos Szeredi 174582a4abSFeng Shuo static bool fuse_use_readdirplus(struct inode *dir, struct file *filp) 184582a4abSFeng Shuo { 194582a4abSFeng Shuo struct fuse_conn *fc = get_fuse_conn(dir); 204582a4abSFeng Shuo struct fuse_inode *fi = get_fuse_inode(dir); 214582a4abSFeng Shuo 224582a4abSFeng Shuo if (!fc->do_readdirplus) 234582a4abSFeng Shuo return false; 24634734b6SEric Wong if (!fc->readdirplus_auto) 25634734b6SEric Wong return true; 264582a4abSFeng Shuo if (test_and_clear_bit(FUSE_I_ADVISE_RDPLUS, &fi->state)) 274582a4abSFeng Shuo return true; 284582a4abSFeng Shuo if (filp->f_pos == 0) 294582a4abSFeng Shuo return true; 304582a4abSFeng Shuo return false; 314582a4abSFeng Shuo } 324582a4abSFeng Shuo 334582a4abSFeng Shuo static void fuse_advise_use_readdirplus(struct inode *dir) 344582a4abSFeng Shuo { 354582a4abSFeng Shuo struct fuse_inode *fi = get_fuse_inode(dir); 364582a4abSFeng Shuo 374582a4abSFeng Shuo set_bit(FUSE_I_ADVISE_RDPLUS, &fi->state); 384582a4abSFeng Shuo } 394582a4abSFeng Shuo 400a0898cfSMiklos Szeredi #if BITS_PER_LONG >= 64 410a0898cfSMiklos Szeredi static inline void fuse_dentry_settime(struct dentry *entry, u64 time) 420a0898cfSMiklos Szeredi { 430a0898cfSMiklos Szeredi entry->d_time = time; 440a0898cfSMiklos Szeredi } 450a0898cfSMiklos Szeredi 460a0898cfSMiklos Szeredi static inline u64 fuse_dentry_time(struct dentry *entry) 470a0898cfSMiklos Szeredi { 480a0898cfSMiklos Szeredi return entry->d_time; 490a0898cfSMiklos Szeredi } 500a0898cfSMiklos Szeredi #else 510a0898cfSMiklos Szeredi /* 520a0898cfSMiklos Szeredi * On 32 bit archs store the high 32 bits of time in d_fsdata 530a0898cfSMiklos Szeredi */ 540a0898cfSMiklos Szeredi static void fuse_dentry_settime(struct dentry *entry, u64 time) 550a0898cfSMiklos Szeredi { 560a0898cfSMiklos Szeredi entry->d_time = time; 570a0898cfSMiklos Szeredi entry->d_fsdata = (void *) (unsigned long) (time >> 32); 580a0898cfSMiklos Szeredi } 590a0898cfSMiklos Szeredi 600a0898cfSMiklos Szeredi static u64 fuse_dentry_time(struct dentry *entry) 610a0898cfSMiklos Szeredi { 620a0898cfSMiklos Szeredi return (u64) entry->d_time + 630a0898cfSMiklos Szeredi ((u64) (unsigned long) entry->d_fsdata << 32); 640a0898cfSMiklos Szeredi } 650a0898cfSMiklos Szeredi #endif 660a0898cfSMiklos Szeredi 676f9f1180SMiklos Szeredi /* 686f9f1180SMiklos Szeredi * FUSE caches dentries and attributes with separate timeout. The 696f9f1180SMiklos Szeredi * time in jiffies until the dentry/attributes are valid is stored in 706f9f1180SMiklos Szeredi * dentry->d_time and fuse_inode->i_time respectively. 716f9f1180SMiklos Szeredi */ 726f9f1180SMiklos Szeredi 736f9f1180SMiklos Szeredi /* 746f9f1180SMiklos Szeredi * Calculate the time in jiffies until a dentry/attributes are valid 756f9f1180SMiklos Szeredi */ 760a0898cfSMiklos Szeredi static u64 time_to_jiffies(unsigned long sec, unsigned long nsec) 77e5e5558eSMiklos Szeredi { 78685d16ddSMiklos Szeredi if (sec || nsec) { 79e5e5558eSMiklos Szeredi struct timespec ts = {sec, nsec}; 800a0898cfSMiklos Szeredi return get_jiffies_64() + timespec_to_jiffies(&ts); 81685d16ddSMiklos Szeredi } else 820a0898cfSMiklos Szeredi return 0; 83e5e5558eSMiklos Szeredi } 84e5e5558eSMiklos Szeredi 856f9f1180SMiklos Szeredi /* 866f9f1180SMiklos Szeredi * Set dentry and possibly attribute timeouts from the lookup/mk* 876f9f1180SMiklos Szeredi * replies 886f9f1180SMiklos Szeredi */ 891fb69e78SMiklos Szeredi static void fuse_change_entry_timeout(struct dentry *entry, 901fb69e78SMiklos Szeredi struct fuse_entry_out *o) 910aa7c699SMiklos Szeredi { 920a0898cfSMiklos Szeredi fuse_dentry_settime(entry, 930a0898cfSMiklos Szeredi time_to_jiffies(o->entry_valid, o->entry_valid_nsec)); 941fb69e78SMiklos Szeredi } 951fb69e78SMiklos Szeredi 961fb69e78SMiklos Szeredi static u64 attr_timeout(struct fuse_attr_out *o) 971fb69e78SMiklos Szeredi { 981fb69e78SMiklos Szeredi return time_to_jiffies(o->attr_valid, o->attr_valid_nsec); 991fb69e78SMiklos Szeredi } 1001fb69e78SMiklos Szeredi 1011fb69e78SMiklos Szeredi static u64 entry_attr_timeout(struct fuse_entry_out *o) 1021fb69e78SMiklos Szeredi { 1031fb69e78SMiklos Szeredi return time_to_jiffies(o->attr_valid, o->attr_valid_nsec); 1048cbdf1e6SMiklos Szeredi } 1058cbdf1e6SMiklos Szeredi 1066f9f1180SMiklos Szeredi /* 1076f9f1180SMiklos Szeredi * Mark the attributes as stale, so that at the next call to 1086f9f1180SMiklos Szeredi * ->getattr() they will be fetched from userspace 1096f9f1180SMiklos Szeredi */ 1108cbdf1e6SMiklos Szeredi void fuse_invalidate_attr(struct inode *inode) 1118cbdf1e6SMiklos Szeredi { 1120a0898cfSMiklos Szeredi get_fuse_inode(inode)->i_time = 0; 1138cbdf1e6SMiklos Szeredi } 1148cbdf1e6SMiklos Szeredi 1156f9f1180SMiklos Szeredi /* 1166f9f1180SMiklos Szeredi * Just mark the entry as stale, so that a next attempt to look it up 1176f9f1180SMiklos Szeredi * will result in a new lookup call to userspace 1186f9f1180SMiklos Szeredi * 1196f9f1180SMiklos Szeredi * This is called when a dentry is about to become negative and the 1206f9f1180SMiklos Szeredi * timeout is unknown (unlink, rmdir, rename and in some cases 1216f9f1180SMiklos Szeredi * lookup) 1226f9f1180SMiklos Szeredi */ 123dbd561d2SMiklos Szeredi void fuse_invalidate_entry_cache(struct dentry *entry) 1248cbdf1e6SMiklos Szeredi { 1250a0898cfSMiklos Szeredi fuse_dentry_settime(entry, 0); 1268cbdf1e6SMiklos Szeredi } 1278cbdf1e6SMiklos Szeredi 1286f9f1180SMiklos Szeredi /* 1296f9f1180SMiklos Szeredi * Same as fuse_invalidate_entry_cache(), but also try to remove the 1306f9f1180SMiklos Szeredi * dentry from the hash 1316f9f1180SMiklos Szeredi */ 1328cbdf1e6SMiklos Szeredi static void fuse_invalidate_entry(struct dentry *entry) 1338cbdf1e6SMiklos Szeredi { 1348cbdf1e6SMiklos Szeredi d_invalidate(entry); 1358cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 1360aa7c699SMiklos Szeredi } 1370aa7c699SMiklos Szeredi 138c180eebeSMiklos Szeredi static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_req *req, 139c180eebeSMiklos Szeredi u64 nodeid, struct qstr *name, 140e5e5558eSMiklos Szeredi struct fuse_entry_out *outarg) 141e5e5558eSMiklos Szeredi { 1420e9663eeSMiklos Szeredi memset(outarg, 0, sizeof(struct fuse_entry_out)); 143e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_LOOKUP; 144c180eebeSMiklos Szeredi req->in.h.nodeid = nodeid; 145e5e5558eSMiklos Szeredi req->in.numargs = 1; 146c180eebeSMiklos Szeredi req->in.args[0].size = name->len + 1; 147c180eebeSMiklos Szeredi req->in.args[0].value = name->name; 148e5e5558eSMiklos Szeredi req->out.numargs = 1; 1490e9663eeSMiklos Szeredi if (fc->minor < 9) 1500e9663eeSMiklos Szeredi req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; 1510e9663eeSMiklos Szeredi else 152e5e5558eSMiklos Szeredi req->out.args[0].size = sizeof(struct fuse_entry_out); 153e5e5558eSMiklos Szeredi req->out.args[0].value = outarg; 154e5e5558eSMiklos Szeredi } 155e5e5558eSMiklos Szeredi 1565c5c5e51SMiklos Szeredi u64 fuse_get_attr_version(struct fuse_conn *fc) 1577dca9fd3SMiklos Szeredi { 1587dca9fd3SMiklos Szeredi u64 curr_version; 1597dca9fd3SMiklos Szeredi 1607dca9fd3SMiklos Szeredi /* 1617dca9fd3SMiklos Szeredi * The spin lock isn't actually needed on 64bit archs, but we 1627dca9fd3SMiklos Szeredi * don't yet care too much about such optimizations. 1637dca9fd3SMiklos Szeredi */ 1647dca9fd3SMiklos Szeredi spin_lock(&fc->lock); 1657dca9fd3SMiklos Szeredi curr_version = fc->attr_version; 1667dca9fd3SMiklos Szeredi spin_unlock(&fc->lock); 1677dca9fd3SMiklos Szeredi 1687dca9fd3SMiklos Szeredi return curr_version; 1697dca9fd3SMiklos Szeredi } 1707dca9fd3SMiklos Szeredi 1716f9f1180SMiklos Szeredi /* 1726f9f1180SMiklos Szeredi * Check whether the dentry is still valid 1736f9f1180SMiklos Szeredi * 1746f9f1180SMiklos Szeredi * If the entry validity timeout has expired and the dentry is 1756f9f1180SMiklos Szeredi * positive, try to redo the lookup. If the lookup results in a 1766f9f1180SMiklos Szeredi * different inode, then let the VFS invalidate the dentry and redo 1776f9f1180SMiklos Szeredi * the lookup once more. If the lookup results in the same inode, 1786f9f1180SMiklos Szeredi * then refresh the attributes, timeouts and mark the dentry valid. 1796f9f1180SMiklos Szeredi */ 1800b728e19SAl Viro static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) 181e5e5558eSMiklos Szeredi { 18234286d66SNick Piggin struct inode *inode; 183*28420dadSMiklos Szeredi struct dentry *parent; 184*28420dadSMiklos Szeredi struct fuse_conn *fc; 1858cbdf1e6SMiklos Szeredi 186e7c0a167SMiklos Szeredi inode = ACCESS_ONCE(entry->d_inode); 1878cbdf1e6SMiklos Szeredi if (inode && is_bad_inode(inode)) 188e5e5558eSMiklos Szeredi return 0; 1890a0898cfSMiklos Szeredi else if (fuse_dentry_time(entry) < get_jiffies_64()) { 190e5e5558eSMiklos Szeredi int err; 191e5e5558eSMiklos Szeredi struct fuse_entry_out outarg; 1928cbdf1e6SMiklos Szeredi struct fuse_req *req; 19307e77dcaSMiklos Szeredi struct fuse_forget_link *forget; 1941fb69e78SMiklos Szeredi u64 attr_version; 1958cbdf1e6SMiklos Szeredi 19650322fe7SMiklos Szeredi /* For negative dentries, always do a fresh lookup */ 1978cbdf1e6SMiklos Szeredi if (!inode) 1988cbdf1e6SMiklos Szeredi return 0; 1998cbdf1e6SMiklos Szeredi 2000b728e19SAl Viro if (flags & LOOKUP_RCU) 201e7c0a167SMiklos Szeredi return -ECHILD; 202e7c0a167SMiklos Szeredi 2038cbdf1e6SMiklos Szeredi fc = get_fuse_conn(inode); 204b111c8c0SMaxim Patlasov req = fuse_get_req_nopages(fc); 205ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 206e5e5558eSMiklos Szeredi return 0; 207e5e5558eSMiklos Szeredi 20807e77dcaSMiklos Szeredi forget = fuse_alloc_forget(); 20907e77dcaSMiklos Szeredi if (!forget) { 2102d51013eSMiklos Szeredi fuse_put_request(fc, req); 2112d51013eSMiklos Szeredi return 0; 2122d51013eSMiklos Szeredi } 2132d51013eSMiklos Szeredi 2147dca9fd3SMiklos Szeredi attr_version = fuse_get_attr_version(fc); 2151fb69e78SMiklos Szeredi 216e956edd0SMiklos Szeredi parent = dget_parent(entry); 217c180eebeSMiklos Szeredi fuse_lookup_init(fc, req, get_node_id(parent->d_inode), 218c180eebeSMiklos Szeredi &entry->d_name, &outarg); 219b93f858aSTejun Heo fuse_request_send(fc, req); 220e956edd0SMiklos Szeredi dput(parent); 221e5e5558eSMiklos Szeredi err = req->out.h.error; 2222d51013eSMiklos Szeredi fuse_put_request(fc, req); 22350322fe7SMiklos Szeredi /* Zero nodeid is same as -ENOENT */ 22450322fe7SMiklos Szeredi if (!err && !outarg.nodeid) 22550322fe7SMiklos Szeredi err = -ENOENT; 2269e6268dbSMiklos Szeredi if (!err) { 2278cbdf1e6SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 2289e6268dbSMiklos Szeredi if (outarg.nodeid != get_node_id(inode)) { 22907e77dcaSMiklos Szeredi fuse_queue_forget(fc, forget, outarg.nodeid, 1); 2309e6268dbSMiklos Szeredi return 0; 2319e6268dbSMiklos Szeredi } 2328da5ff23SMiklos Szeredi spin_lock(&fc->lock); 2339e6268dbSMiklos Szeredi fi->nlookup++; 2348da5ff23SMiklos Szeredi spin_unlock(&fc->lock); 2359e6268dbSMiklos Szeredi } 23607e77dcaSMiklos Szeredi kfree(forget); 2379e6268dbSMiklos Szeredi if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) 238e5e5558eSMiklos Szeredi return 0; 239e5e5558eSMiklos Szeredi 2401fb69e78SMiklos Szeredi fuse_change_attributes(inode, &outarg.attr, 2411fb69e78SMiklos Szeredi entry_attr_timeout(&outarg), 2421fb69e78SMiklos Szeredi attr_version); 2431fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outarg); 244*28420dadSMiklos Szeredi } else if (inode) { 245*28420dadSMiklos Szeredi fc = get_fuse_conn(inode); 246*28420dadSMiklos Szeredi if (fc->readdirplus_auto) { 247*28420dadSMiklos Szeredi parent = dget_parent(entry); 248*28420dadSMiklos Szeredi fuse_advise_use_readdirplus(parent->d_inode); 249*28420dadSMiklos Szeredi dput(parent); 250e5e5558eSMiklos Szeredi } 251*28420dadSMiklos Szeredi } 252e5e5558eSMiklos Szeredi return 1; 253e5e5558eSMiklos Szeredi } 254e5e5558eSMiklos Szeredi 2558bfc016dSMiklos Szeredi static int invalid_nodeid(u64 nodeid) 2562827d0b2SMiklos Szeredi { 2572827d0b2SMiklos Szeredi return !nodeid || nodeid == FUSE_ROOT_ID; 2582827d0b2SMiklos Szeredi } 2592827d0b2SMiklos Szeredi 2604269590aSAl Viro const struct dentry_operations fuse_dentry_operations = { 261e5e5558eSMiklos Szeredi .d_revalidate = fuse_dentry_revalidate, 262e5e5558eSMiklos Szeredi }; 263e5e5558eSMiklos Szeredi 264a5bfffacSTimo Savola int fuse_valid_type(int m) 26539ee059aSMiklos Szeredi { 26639ee059aSMiklos Szeredi return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) || 26739ee059aSMiklos Szeredi S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); 26839ee059aSMiklos Szeredi } 26939ee059aSMiklos Szeredi 270d2a85164SMiklos Szeredi /* 271d2a85164SMiklos Szeredi * Add a directory inode to a dentry, ensuring that no other dentry 272d2a85164SMiklos Szeredi * refers to this inode. Called with fc->inst_mutex. 273d2a85164SMiklos Szeredi */ 2740de6256dSMiklos Szeredi static struct dentry *fuse_d_add_directory(struct dentry *entry, 2750de6256dSMiklos Szeredi struct inode *inode) 276d2a85164SMiklos Szeredi { 277d2a85164SMiklos Szeredi struct dentry *alias = d_find_alias(inode); 2780de6256dSMiklos Szeredi if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) { 279d2a85164SMiklos Szeredi /* This tries to shrink the subtree below alias */ 280d2a85164SMiklos Szeredi fuse_invalidate_entry(alias); 281d2a85164SMiklos Szeredi dput(alias); 282b3d9b7a3SAl Viro if (!hlist_empty(&inode->i_dentry)) 2830de6256dSMiklos Szeredi return ERR_PTR(-EBUSY); 2840de6256dSMiklos Szeredi } else { 2850de6256dSMiklos Szeredi dput(alias); 286d2a85164SMiklos Szeredi } 2870de6256dSMiklos Szeredi return d_splice_alias(inode, entry); 288d2a85164SMiklos Szeredi } 289d2a85164SMiklos Szeredi 290c180eebeSMiklos Szeredi int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, 291c180eebeSMiklos Szeredi struct fuse_entry_out *outarg, struct inode **inode) 292c180eebeSMiklos Szeredi { 293c180eebeSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(sb); 294c180eebeSMiklos Szeredi struct fuse_req *req; 29507e77dcaSMiklos Szeredi struct fuse_forget_link *forget; 296c180eebeSMiklos Szeredi u64 attr_version; 297c180eebeSMiklos Szeredi int err; 298c180eebeSMiklos Szeredi 299c180eebeSMiklos Szeredi *inode = NULL; 300c180eebeSMiklos Szeredi err = -ENAMETOOLONG; 301c180eebeSMiklos Szeredi if (name->len > FUSE_NAME_MAX) 302c180eebeSMiklos Szeredi goto out; 303c180eebeSMiklos Szeredi 304b111c8c0SMaxim Patlasov req = fuse_get_req_nopages(fc); 305c180eebeSMiklos Szeredi err = PTR_ERR(req); 306c180eebeSMiklos Szeredi if (IS_ERR(req)) 307c180eebeSMiklos Szeredi goto out; 308c180eebeSMiklos Szeredi 30907e77dcaSMiklos Szeredi forget = fuse_alloc_forget(); 31007e77dcaSMiklos Szeredi err = -ENOMEM; 31107e77dcaSMiklos Szeredi if (!forget) { 312c180eebeSMiklos Szeredi fuse_put_request(fc, req); 313c180eebeSMiklos Szeredi goto out; 314c180eebeSMiklos Szeredi } 315c180eebeSMiklos Szeredi 316c180eebeSMiklos Szeredi attr_version = fuse_get_attr_version(fc); 317c180eebeSMiklos Szeredi 318c180eebeSMiklos Szeredi fuse_lookup_init(fc, req, nodeid, name, outarg); 319b93f858aSTejun Heo fuse_request_send(fc, req); 320c180eebeSMiklos Szeredi err = req->out.h.error; 321c180eebeSMiklos Szeredi fuse_put_request(fc, req); 322c180eebeSMiklos Szeredi /* Zero nodeid is same as -ENOENT, but with valid timeout */ 323c180eebeSMiklos Szeredi if (err || !outarg->nodeid) 324c180eebeSMiklos Szeredi goto out_put_forget; 325c180eebeSMiklos Szeredi 326c180eebeSMiklos Szeredi err = -EIO; 327c180eebeSMiklos Szeredi if (!outarg->nodeid) 328c180eebeSMiklos Szeredi goto out_put_forget; 329c180eebeSMiklos Szeredi if (!fuse_valid_type(outarg->attr.mode)) 330c180eebeSMiklos Szeredi goto out_put_forget; 331c180eebeSMiklos Szeredi 332c180eebeSMiklos Szeredi *inode = fuse_iget(sb, outarg->nodeid, outarg->generation, 333c180eebeSMiklos Szeredi &outarg->attr, entry_attr_timeout(outarg), 334c180eebeSMiklos Szeredi attr_version); 335c180eebeSMiklos Szeredi err = -ENOMEM; 336c180eebeSMiklos Szeredi if (!*inode) { 33707e77dcaSMiklos Szeredi fuse_queue_forget(fc, forget, outarg->nodeid, 1); 338c180eebeSMiklos Szeredi goto out; 339c180eebeSMiklos Szeredi } 340c180eebeSMiklos Szeredi err = 0; 341c180eebeSMiklos Szeredi 342c180eebeSMiklos Szeredi out_put_forget: 34307e77dcaSMiklos Szeredi kfree(forget); 344c180eebeSMiklos Szeredi out: 345c180eebeSMiklos Szeredi return err; 346c180eebeSMiklos Szeredi } 347c180eebeSMiklos Szeredi 3480aa7c699SMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, 34900cd8dd3SAl Viro unsigned int flags) 350e5e5558eSMiklos Szeredi { 351e5e5558eSMiklos Szeredi int err; 352e5e5558eSMiklos Szeredi struct fuse_entry_out outarg; 353c180eebeSMiklos Szeredi struct inode *inode; 3540de6256dSMiklos Szeredi struct dentry *newent; 355e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 356c180eebeSMiklos Szeredi bool outarg_valid = true; 357e5e5558eSMiklos Szeredi 358c180eebeSMiklos Szeredi err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name, 359c180eebeSMiklos Szeredi &outarg, &inode); 360c180eebeSMiklos Szeredi if (err == -ENOENT) { 361c180eebeSMiklos Szeredi outarg_valid = false; 362c180eebeSMiklos Szeredi err = 0; 3632d51013eSMiklos Szeredi } 364c180eebeSMiklos Szeredi if (err) 365c180eebeSMiklos Szeredi goto out_err; 3662d51013eSMiklos Szeredi 367ee4e5271SMiklos Szeredi err = -EIO; 368c180eebeSMiklos Szeredi if (inode && get_node_id(inode) == FUSE_ROOT_ID) 369c180eebeSMiklos Szeredi goto out_iput; 370e5e5558eSMiklos Szeredi 371d2a85164SMiklos Szeredi if (inode && S_ISDIR(inode->i_mode)) { 372d2a85164SMiklos Szeredi mutex_lock(&fc->inst_mutex); 3730de6256dSMiklos Szeredi newent = fuse_d_add_directory(entry, inode); 374d2a85164SMiklos Szeredi mutex_unlock(&fc->inst_mutex); 375c180eebeSMiklos Szeredi err = PTR_ERR(newent); 376c180eebeSMiklos Szeredi if (IS_ERR(newent)) 377c180eebeSMiklos Szeredi goto out_iput; 378c180eebeSMiklos Szeredi } else { 3790de6256dSMiklos Szeredi newent = d_splice_alias(inode, entry); 380c180eebeSMiklos Szeredi } 381d2a85164SMiklos Szeredi 3820de6256dSMiklos Szeredi entry = newent ? newent : entry; 383c180eebeSMiklos Szeredi if (outarg_valid) 3841fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outarg); 3858cbdf1e6SMiklos Szeredi else 3868cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 387c180eebeSMiklos Szeredi 3884582a4abSFeng Shuo fuse_advise_use_readdirplus(dir); 3890de6256dSMiklos Szeredi return newent; 390c180eebeSMiklos Szeredi 391c180eebeSMiklos Szeredi out_iput: 392c180eebeSMiklos Szeredi iput(inode); 393c180eebeSMiklos Szeredi out_err: 394c180eebeSMiklos Szeredi return ERR_PTR(err); 395e5e5558eSMiklos Szeredi } 396e5e5558eSMiklos Szeredi 3976f9f1180SMiklos Szeredi /* 3986f9f1180SMiklos Szeredi * Atomic create+open operation 3996f9f1180SMiklos Szeredi * 4006f9f1180SMiklos Szeredi * If the filesystem doesn't support this, then fall back to separate 4016f9f1180SMiklos Szeredi * 'mknod' + 'open' requests. 4026f9f1180SMiklos Szeredi */ 403d9585277SAl Viro static int fuse_create_open(struct inode *dir, struct dentry *entry, 40430d90494SAl Viro struct file *file, unsigned flags, 40547237687SAl Viro umode_t mode, int *opened) 406fd72faacSMiklos Szeredi { 407fd72faacSMiklos Szeredi int err; 408fd72faacSMiklos Szeredi struct inode *inode; 409fd72faacSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 410fd72faacSMiklos Szeredi struct fuse_req *req; 41107e77dcaSMiklos Szeredi struct fuse_forget_link *forget; 412e0a43ddcSMiklos Szeredi struct fuse_create_in inarg; 413fd72faacSMiklos Szeredi struct fuse_open_out outopen; 414fd72faacSMiklos Szeredi struct fuse_entry_out outentry; 415fd72faacSMiklos Szeredi struct fuse_file *ff; 416fd72faacSMiklos Szeredi 417af109bcaSMiklos Szeredi /* Userspace expects S_IFREG in create mode */ 418af109bcaSMiklos Szeredi BUG_ON((mode & S_IFMT) != S_IFREG); 419af109bcaSMiklos Szeredi 42007e77dcaSMiklos Szeredi forget = fuse_alloc_forget(); 421c8ccbe03SMiklos Szeredi err = -ENOMEM; 42207e77dcaSMiklos Szeredi if (!forget) 423c8ccbe03SMiklos Szeredi goto out_err; 42451eb01e7SMiklos Szeredi 425b111c8c0SMaxim Patlasov req = fuse_get_req_nopages(fc); 42651eb01e7SMiklos Szeredi err = PTR_ERR(req); 427ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 42851eb01e7SMiklos Szeredi goto out_put_forget_req; 429fd72faacSMiklos Szeredi 430ce1d5a49SMiklos Szeredi err = -ENOMEM; 431acf99433STejun Heo ff = fuse_file_alloc(fc); 432fd72faacSMiklos Szeredi if (!ff) 433fd72faacSMiklos Szeredi goto out_put_request; 434fd72faacSMiklos Szeredi 435e0a43ddcSMiklos Szeredi if (!fc->dont_mask) 436e0a43ddcSMiklos Szeredi mode &= ~current_umask(); 437e0a43ddcSMiklos Szeredi 438fd72faacSMiklos Szeredi flags &= ~O_NOCTTY; 439fd72faacSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 4400e9663eeSMiklos Szeredi memset(&outentry, 0, sizeof(outentry)); 441fd72faacSMiklos Szeredi inarg.flags = flags; 442fd72faacSMiklos Szeredi inarg.mode = mode; 443e0a43ddcSMiklos Szeredi inarg.umask = current_umask(); 444fd72faacSMiklos Szeredi req->in.h.opcode = FUSE_CREATE; 445fd72faacSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 446fd72faacSMiklos Szeredi req->in.numargs = 2; 447e0a43ddcSMiklos Szeredi req->in.args[0].size = fc->minor < 12 ? sizeof(struct fuse_open_in) : 448e0a43ddcSMiklos Szeredi sizeof(inarg); 449fd72faacSMiklos Szeredi req->in.args[0].value = &inarg; 450fd72faacSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 451fd72faacSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 452fd72faacSMiklos Szeredi req->out.numargs = 2; 4530e9663eeSMiklos Szeredi if (fc->minor < 9) 4540e9663eeSMiklos Szeredi req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; 4550e9663eeSMiklos Szeredi else 456fd72faacSMiklos Szeredi req->out.args[0].size = sizeof(outentry); 457fd72faacSMiklos Szeredi req->out.args[0].value = &outentry; 458fd72faacSMiklos Szeredi req->out.args[1].size = sizeof(outopen); 459fd72faacSMiklos Szeredi req->out.args[1].value = &outopen; 460b93f858aSTejun Heo fuse_request_send(fc, req); 461fd72faacSMiklos Szeredi err = req->out.h.error; 462c8ccbe03SMiklos Szeredi if (err) 463fd72faacSMiklos Szeredi goto out_free_ff; 464fd72faacSMiklos Szeredi 465fd72faacSMiklos Szeredi err = -EIO; 4662827d0b2SMiklos Szeredi if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid)) 467fd72faacSMiklos Szeredi goto out_free_ff; 468fd72faacSMiklos Szeredi 46951eb01e7SMiklos Szeredi fuse_put_request(fc, req); 470c7b7143cSMiklos Szeredi ff->fh = outopen.fh; 471c7b7143cSMiklos Szeredi ff->nodeid = outentry.nodeid; 472c7b7143cSMiklos Szeredi ff->open_flags = outopen.open_flags; 473fd72faacSMiklos Szeredi inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, 4741fb69e78SMiklos Szeredi &outentry.attr, entry_attr_timeout(&outentry), 0); 475fd72faacSMiklos Szeredi if (!inode) { 476fd72faacSMiklos Szeredi flags &= ~(O_CREAT | O_EXCL | O_TRUNC); 4778b0797a4SMiklos Szeredi fuse_sync_release(ff, flags); 47807e77dcaSMiklos Szeredi fuse_queue_forget(fc, forget, outentry.nodeid, 1); 479c8ccbe03SMiklos Szeredi err = -ENOMEM; 480c8ccbe03SMiklos Szeredi goto out_err; 481fd72faacSMiklos Szeredi } 48207e77dcaSMiklos Szeredi kfree(forget); 483fd72faacSMiklos Szeredi d_instantiate(entry, inode); 4841fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outentry); 4850952b2a4SMiklos Szeredi fuse_invalidate_attr(dir); 48630d90494SAl Viro err = finish_open(file, entry, generic_file_open, opened); 48730d90494SAl Viro if (err) { 4888b0797a4SMiklos Szeredi fuse_sync_release(ff, flags); 489c8ccbe03SMiklos Szeredi } else { 490c7b7143cSMiklos Szeredi file->private_data = fuse_file_get(ff); 491c7b7143cSMiklos Szeredi fuse_finish_open(inode, file); 492c8ccbe03SMiklos Szeredi } 493d9585277SAl Viro return err; 494fd72faacSMiklos Szeredi 495fd72faacSMiklos Szeredi out_free_ff: 496fd72faacSMiklos Szeredi fuse_file_free(ff); 497fd72faacSMiklos Szeredi out_put_request: 498fd72faacSMiklos Szeredi fuse_put_request(fc, req); 49951eb01e7SMiklos Szeredi out_put_forget_req: 50007e77dcaSMiklos Szeredi kfree(forget); 501c8ccbe03SMiklos Szeredi out_err: 502d9585277SAl Viro return err; 503c8ccbe03SMiklos Szeredi } 504c8ccbe03SMiklos Szeredi 505c8ccbe03SMiklos Szeredi static int fuse_mknod(struct inode *, struct dentry *, umode_t, dev_t); 506d9585277SAl Viro static int fuse_atomic_open(struct inode *dir, struct dentry *entry, 50730d90494SAl Viro struct file *file, unsigned flags, 50847237687SAl Viro umode_t mode, int *opened) 509c8ccbe03SMiklos Szeredi { 510c8ccbe03SMiklos Szeredi int err; 511c8ccbe03SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 512c8ccbe03SMiklos Szeredi struct dentry *res = NULL; 513c8ccbe03SMiklos Szeredi 514c8ccbe03SMiklos Szeredi if (d_unhashed(entry)) { 51500cd8dd3SAl Viro res = fuse_lookup(dir, entry, 0); 516c8ccbe03SMiklos Szeredi if (IS_ERR(res)) 517d9585277SAl Viro return PTR_ERR(res); 518c8ccbe03SMiklos Szeredi 519c8ccbe03SMiklos Szeredi if (res) 520c8ccbe03SMiklos Szeredi entry = res; 521c8ccbe03SMiklos Szeredi } 522c8ccbe03SMiklos Szeredi 523c8ccbe03SMiklos Szeredi if (!(flags & O_CREAT) || entry->d_inode) 524c8ccbe03SMiklos Szeredi goto no_open; 525c8ccbe03SMiklos Szeredi 526c8ccbe03SMiklos Szeredi /* Only creates */ 52747237687SAl Viro *opened |= FILE_CREATED; 528c8ccbe03SMiklos Szeredi 529c8ccbe03SMiklos Szeredi if (fc->no_create) 530c8ccbe03SMiklos Szeredi goto mknod; 531c8ccbe03SMiklos Szeredi 53230d90494SAl Viro err = fuse_create_open(dir, entry, file, flags, mode, opened); 533d9585277SAl Viro if (err == -ENOSYS) { 534c8ccbe03SMiklos Szeredi fc->no_create = 1; 535c8ccbe03SMiklos Szeredi goto mknod; 536c8ccbe03SMiklos Szeredi } 537c8ccbe03SMiklos Szeredi out_dput: 538c8ccbe03SMiklos Szeredi dput(res); 539d9585277SAl Viro return err; 540c8ccbe03SMiklos Szeredi 541c8ccbe03SMiklos Szeredi mknod: 542c8ccbe03SMiklos Szeredi err = fuse_mknod(dir, entry, mode, 0); 543d9585277SAl Viro if (err) 544c8ccbe03SMiklos Szeredi goto out_dput; 545c8ccbe03SMiklos Szeredi no_open: 546e45198a6SAl Viro return finish_no_open(file, res); 547fd72faacSMiklos Szeredi } 548fd72faacSMiklos Szeredi 5496f9f1180SMiklos Szeredi /* 5506f9f1180SMiklos Szeredi * Code shared between mknod, mkdir, symlink and link 5516f9f1180SMiklos Szeredi */ 5529e6268dbSMiklos Szeredi static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, 5539e6268dbSMiklos Szeredi struct inode *dir, struct dentry *entry, 554541af6a0SAl Viro umode_t mode) 5559e6268dbSMiklos Szeredi { 5569e6268dbSMiklos Szeredi struct fuse_entry_out outarg; 5579e6268dbSMiklos Szeredi struct inode *inode; 5589e6268dbSMiklos Szeredi int err; 55907e77dcaSMiklos Szeredi struct fuse_forget_link *forget; 5602d51013eSMiklos Szeredi 56107e77dcaSMiklos Szeredi forget = fuse_alloc_forget(); 56207e77dcaSMiklos Szeredi if (!forget) { 5632d51013eSMiklos Szeredi fuse_put_request(fc, req); 56407e77dcaSMiklos Szeredi return -ENOMEM; 5652d51013eSMiklos Szeredi } 5669e6268dbSMiklos Szeredi 5670e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 5689e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 5699e6268dbSMiklos Szeredi req->out.numargs = 1; 5700e9663eeSMiklos Szeredi if (fc->minor < 9) 5710e9663eeSMiklos Szeredi req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; 5720e9663eeSMiklos Szeredi else 5739e6268dbSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 5749e6268dbSMiklos Szeredi req->out.args[0].value = &outarg; 575b93f858aSTejun Heo fuse_request_send(fc, req); 5769e6268dbSMiklos Szeredi err = req->out.h.error; 5779e6268dbSMiklos Szeredi fuse_put_request(fc, req); 5782d51013eSMiklos Szeredi if (err) 5792d51013eSMiklos Szeredi goto out_put_forget_req; 5802d51013eSMiklos Szeredi 58139ee059aSMiklos Szeredi err = -EIO; 58239ee059aSMiklos Szeredi if (invalid_nodeid(outarg.nodeid)) 5832d51013eSMiklos Szeredi goto out_put_forget_req; 58439ee059aSMiklos Szeredi 58539ee059aSMiklos Szeredi if ((outarg.attr.mode ^ mode) & S_IFMT) 5862d51013eSMiklos Szeredi goto out_put_forget_req; 58739ee059aSMiklos Szeredi 5889e6268dbSMiklos Szeredi inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 5891fb69e78SMiklos Szeredi &outarg.attr, entry_attr_timeout(&outarg), 0); 5909e6268dbSMiklos Szeredi if (!inode) { 59107e77dcaSMiklos Szeredi fuse_queue_forget(fc, forget, outarg.nodeid, 1); 5929e6268dbSMiklos Szeredi return -ENOMEM; 5939e6268dbSMiklos Szeredi } 59407e77dcaSMiklos Szeredi kfree(forget); 5959e6268dbSMiklos Szeredi 596d2a85164SMiklos Szeredi if (S_ISDIR(inode->i_mode)) { 597d2a85164SMiklos Szeredi struct dentry *alias; 598d2a85164SMiklos Szeredi mutex_lock(&fc->inst_mutex); 599d2a85164SMiklos Szeredi alias = d_find_alias(inode); 600d2a85164SMiklos Szeredi if (alias) { 601d2a85164SMiklos Szeredi /* New directory must have moved since mkdir */ 602d2a85164SMiklos Szeredi mutex_unlock(&fc->inst_mutex); 603d2a85164SMiklos Szeredi dput(alias); 6049e6268dbSMiklos Szeredi iput(inode); 605d2a85164SMiklos Szeredi return -EBUSY; 6069e6268dbSMiklos Szeredi } 6079e6268dbSMiklos Szeredi d_instantiate(entry, inode); 608d2a85164SMiklos Szeredi mutex_unlock(&fc->inst_mutex); 609d2a85164SMiklos Szeredi } else 610d2a85164SMiklos Szeredi d_instantiate(entry, inode); 611d2a85164SMiklos Szeredi 6121fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outarg); 6139e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 6149e6268dbSMiklos Szeredi return 0; 61539ee059aSMiklos Szeredi 6162d51013eSMiklos Szeredi out_put_forget_req: 61707e77dcaSMiklos Szeredi kfree(forget); 61839ee059aSMiklos Szeredi return err; 6199e6268dbSMiklos Szeredi } 6209e6268dbSMiklos Szeredi 6211a67aafbSAl Viro static int fuse_mknod(struct inode *dir, struct dentry *entry, umode_t mode, 6229e6268dbSMiklos Szeredi dev_t rdev) 6239e6268dbSMiklos Szeredi { 6249e6268dbSMiklos Szeredi struct fuse_mknod_in inarg; 6259e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 626b111c8c0SMaxim Patlasov struct fuse_req *req = fuse_get_req_nopages(fc); 627ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 628ce1d5a49SMiklos Szeredi return PTR_ERR(req); 6299e6268dbSMiklos Szeredi 630e0a43ddcSMiklos Szeredi if (!fc->dont_mask) 631e0a43ddcSMiklos Szeredi mode &= ~current_umask(); 632e0a43ddcSMiklos Szeredi 6339e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 6349e6268dbSMiklos Szeredi inarg.mode = mode; 6359e6268dbSMiklos Szeredi inarg.rdev = new_encode_dev(rdev); 636e0a43ddcSMiklos Szeredi inarg.umask = current_umask(); 6379e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_MKNOD; 6389e6268dbSMiklos Szeredi req->in.numargs = 2; 639e0a43ddcSMiklos Szeredi req->in.args[0].size = fc->minor < 12 ? FUSE_COMPAT_MKNOD_IN_SIZE : 640e0a43ddcSMiklos Szeredi sizeof(inarg); 6419e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 6429e6268dbSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 6439e6268dbSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 6449e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, mode); 6459e6268dbSMiklos Szeredi } 6469e6268dbSMiklos Szeredi 6474acdaf27SAl Viro static int fuse_create(struct inode *dir, struct dentry *entry, umode_t mode, 648ebfc3b49SAl Viro bool excl) 6499e6268dbSMiklos Szeredi { 6509e6268dbSMiklos Szeredi return fuse_mknod(dir, entry, mode, 0); 6519e6268dbSMiklos Szeredi } 6529e6268dbSMiklos Szeredi 65318bb1db3SAl Viro static int fuse_mkdir(struct inode *dir, struct dentry *entry, umode_t mode) 6549e6268dbSMiklos Szeredi { 6559e6268dbSMiklos Szeredi struct fuse_mkdir_in inarg; 6569e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 657b111c8c0SMaxim Patlasov struct fuse_req *req = fuse_get_req_nopages(fc); 658ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 659ce1d5a49SMiklos Szeredi return PTR_ERR(req); 6609e6268dbSMiklos Szeredi 661e0a43ddcSMiklos Szeredi if (!fc->dont_mask) 662e0a43ddcSMiklos Szeredi mode &= ~current_umask(); 663e0a43ddcSMiklos Szeredi 6649e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 6659e6268dbSMiklos Szeredi inarg.mode = mode; 666e0a43ddcSMiklos Szeredi inarg.umask = current_umask(); 6679e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_MKDIR; 6689e6268dbSMiklos Szeredi req->in.numargs = 2; 6699e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 6709e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 6719e6268dbSMiklos Szeredi req->in.args[1].size = entry->d_name.len + 1; 6729e6268dbSMiklos Szeredi req->in.args[1].value = entry->d_name.name; 6739e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, S_IFDIR); 6749e6268dbSMiklos Szeredi } 6759e6268dbSMiklos Szeredi 6769e6268dbSMiklos Szeredi static int fuse_symlink(struct inode *dir, struct dentry *entry, 6779e6268dbSMiklos Szeredi const char *link) 6789e6268dbSMiklos Szeredi { 6799e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 6809e6268dbSMiklos Szeredi unsigned len = strlen(link) + 1; 681b111c8c0SMaxim Patlasov struct fuse_req *req = fuse_get_req_nopages(fc); 682ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 683ce1d5a49SMiklos Szeredi return PTR_ERR(req); 6849e6268dbSMiklos Szeredi 6859e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_SYMLINK; 6869e6268dbSMiklos Szeredi req->in.numargs = 2; 6879e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 6889e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 6899e6268dbSMiklos Szeredi req->in.args[1].size = len; 6909e6268dbSMiklos Szeredi req->in.args[1].value = link; 6919e6268dbSMiklos Szeredi return create_new_entry(fc, req, dir, entry, S_IFLNK); 6929e6268dbSMiklos Szeredi } 6939e6268dbSMiklos Szeredi 6949e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry) 6959e6268dbSMiklos Szeredi { 6969e6268dbSMiklos Szeredi int err; 6979e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 698b111c8c0SMaxim Patlasov struct fuse_req *req = fuse_get_req_nopages(fc); 699ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 700ce1d5a49SMiklos Szeredi return PTR_ERR(req); 7019e6268dbSMiklos Szeredi 7029e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_UNLINK; 7039e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 7049e6268dbSMiklos Szeredi req->in.numargs = 1; 7059e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 7069e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 707b93f858aSTejun Heo fuse_request_send(fc, req); 7089e6268dbSMiklos Szeredi err = req->out.h.error; 7099e6268dbSMiklos Szeredi fuse_put_request(fc, req); 7109e6268dbSMiklos Szeredi if (!err) { 7119e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 712ac45d613SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 7139e6268dbSMiklos Szeredi 714ac45d613SMiklos Szeredi spin_lock(&fc->lock); 715ac45d613SMiklos Szeredi fi->attr_version = ++fc->attr_version; 716dfca7cebSMiklos Szeredi /* 717dfca7cebSMiklos Szeredi * If i_nlink == 0 then unlink doesn't make sense, yet this can 718dfca7cebSMiklos Szeredi * happen if userspace filesystem is careless. It would be 719dfca7cebSMiklos Szeredi * difficult to enforce correct nlink usage so just ignore this 720dfca7cebSMiklos Szeredi * condition here 721dfca7cebSMiklos Szeredi */ 722dfca7cebSMiklos Szeredi if (inode->i_nlink > 0) 723ac45d613SMiklos Szeredi drop_nlink(inode); 724ac45d613SMiklos Szeredi spin_unlock(&fc->lock); 7259e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 7269e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 7278cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 7289e6268dbSMiklos Szeredi } else if (err == -EINTR) 7299e6268dbSMiklos Szeredi fuse_invalidate_entry(entry); 7309e6268dbSMiklos Szeredi return err; 7319e6268dbSMiklos Szeredi } 7329e6268dbSMiklos Szeredi 7339e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry) 7349e6268dbSMiklos Szeredi { 7359e6268dbSMiklos Szeredi int err; 7369e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 737b111c8c0SMaxim Patlasov struct fuse_req *req = fuse_get_req_nopages(fc); 738ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 739ce1d5a49SMiklos Szeredi return PTR_ERR(req); 7409e6268dbSMiklos Szeredi 7419e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_RMDIR; 7429e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(dir); 7439e6268dbSMiklos Szeredi req->in.numargs = 1; 7449e6268dbSMiklos Szeredi req->in.args[0].size = entry->d_name.len + 1; 7459e6268dbSMiklos Szeredi req->in.args[0].value = entry->d_name.name; 746b93f858aSTejun Heo fuse_request_send(fc, req); 7479e6268dbSMiklos Szeredi err = req->out.h.error; 7489e6268dbSMiklos Szeredi fuse_put_request(fc, req); 7499e6268dbSMiklos Szeredi if (!err) { 750ce71ec36SDave Hansen clear_nlink(entry->d_inode); 7519e6268dbSMiklos Szeredi fuse_invalidate_attr(dir); 7528cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry); 7539e6268dbSMiklos Szeredi } else if (err == -EINTR) 7549e6268dbSMiklos Szeredi fuse_invalidate_entry(entry); 7559e6268dbSMiklos Szeredi return err; 7569e6268dbSMiklos Szeredi } 7579e6268dbSMiklos Szeredi 7589e6268dbSMiklos Szeredi static int fuse_rename(struct inode *olddir, struct dentry *oldent, 7599e6268dbSMiklos Szeredi struct inode *newdir, struct dentry *newent) 7609e6268dbSMiklos Szeredi { 7619e6268dbSMiklos Szeredi int err; 7629e6268dbSMiklos Szeredi struct fuse_rename_in inarg; 7639e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(olddir); 764b111c8c0SMaxim Patlasov struct fuse_req *req = fuse_get_req_nopages(fc); 765e4eaac06SSage Weil 766ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 767ce1d5a49SMiklos Szeredi return PTR_ERR(req); 7689e6268dbSMiklos Szeredi 7699e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 7709e6268dbSMiklos Szeredi inarg.newdir = get_node_id(newdir); 7719e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_RENAME; 7729e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(olddir); 7739e6268dbSMiklos Szeredi req->in.numargs = 3; 7749e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 7759e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 7769e6268dbSMiklos Szeredi req->in.args[1].size = oldent->d_name.len + 1; 7779e6268dbSMiklos Szeredi req->in.args[1].value = oldent->d_name.name; 7789e6268dbSMiklos Szeredi req->in.args[2].size = newent->d_name.len + 1; 7799e6268dbSMiklos Szeredi req->in.args[2].value = newent->d_name.name; 780b93f858aSTejun Heo fuse_request_send(fc, req); 7819e6268dbSMiklos Szeredi err = req->out.h.error; 7829e6268dbSMiklos Szeredi fuse_put_request(fc, req); 7839e6268dbSMiklos Szeredi if (!err) { 78408b63307SMiklos Szeredi /* ctime changes */ 78508b63307SMiklos Szeredi fuse_invalidate_attr(oldent->d_inode); 78608b63307SMiklos Szeredi 7879e6268dbSMiklos Szeredi fuse_invalidate_attr(olddir); 7889e6268dbSMiklos Szeredi if (olddir != newdir) 7899e6268dbSMiklos Szeredi fuse_invalidate_attr(newdir); 7908cbdf1e6SMiklos Szeredi 7918cbdf1e6SMiklos Szeredi /* newent will end up negative */ 7925219f346SMiklos Szeredi if (newent->d_inode) { 7935219f346SMiklos Szeredi fuse_invalidate_attr(newent->d_inode); 7948cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(newent); 7955219f346SMiklos Szeredi } 7969e6268dbSMiklos Szeredi } else if (err == -EINTR) { 7979e6268dbSMiklos Szeredi /* If request was interrupted, DEITY only knows if the 7989e6268dbSMiklos Szeredi rename actually took place. If the invalidation 7999e6268dbSMiklos Szeredi fails (e.g. some process has CWD under the renamed 8009e6268dbSMiklos Szeredi directory), then there can be inconsistency between 8019e6268dbSMiklos Szeredi the dcache and the real filesystem. Tough luck. */ 8029e6268dbSMiklos Szeredi fuse_invalidate_entry(oldent); 8039e6268dbSMiklos Szeredi if (newent->d_inode) 8049e6268dbSMiklos Szeredi fuse_invalidate_entry(newent); 8059e6268dbSMiklos Szeredi } 8069e6268dbSMiklos Szeredi 8079e6268dbSMiklos Szeredi return err; 8089e6268dbSMiklos Szeredi } 8099e6268dbSMiklos Szeredi 8109e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir, 8119e6268dbSMiklos Szeredi struct dentry *newent) 8129e6268dbSMiklos Szeredi { 8139e6268dbSMiklos Szeredi int err; 8149e6268dbSMiklos Szeredi struct fuse_link_in inarg; 8159e6268dbSMiklos Szeredi struct inode *inode = entry->d_inode; 8169e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 817b111c8c0SMaxim Patlasov struct fuse_req *req = fuse_get_req_nopages(fc); 818ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 819ce1d5a49SMiklos Szeredi return PTR_ERR(req); 8209e6268dbSMiklos Szeredi 8219e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 8229e6268dbSMiklos Szeredi inarg.oldnodeid = get_node_id(inode); 8239e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_LINK; 8249e6268dbSMiklos Szeredi req->in.numargs = 2; 8259e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 8269e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 8279e6268dbSMiklos Szeredi req->in.args[1].size = newent->d_name.len + 1; 8289e6268dbSMiklos Szeredi req->in.args[1].value = newent->d_name.name; 8299e6268dbSMiklos Szeredi err = create_new_entry(fc, req, newdir, newent, inode->i_mode); 8309e6268dbSMiklos Szeredi /* Contrary to "normal" filesystems it can happen that link 8319e6268dbSMiklos Szeredi makes two "logical" inodes point to the same "physical" 8329e6268dbSMiklos Szeredi inode. We invalidate the attributes of the old one, so it 8339e6268dbSMiklos Szeredi will reflect changes in the backing inode (link count, 8349e6268dbSMiklos Szeredi etc.) 8359e6268dbSMiklos Szeredi */ 836ac45d613SMiklos Szeredi if (!err) { 837ac45d613SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 838ac45d613SMiklos Szeredi 839ac45d613SMiklos Szeredi spin_lock(&fc->lock); 840ac45d613SMiklos Szeredi fi->attr_version = ++fc->attr_version; 841ac45d613SMiklos Szeredi inc_nlink(inode); 842ac45d613SMiklos Szeredi spin_unlock(&fc->lock); 8439e6268dbSMiklos Szeredi fuse_invalidate_attr(inode); 844ac45d613SMiklos Szeredi } else if (err == -EINTR) { 845ac45d613SMiklos Szeredi fuse_invalidate_attr(inode); 846ac45d613SMiklos Szeredi } 8479e6268dbSMiklos Szeredi return err; 8489e6268dbSMiklos Szeredi } 8499e6268dbSMiklos Szeredi 8501fb69e78SMiklos Szeredi static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, 8511fb69e78SMiklos Szeredi struct kstat *stat) 8521fb69e78SMiklos Szeredi { 853203627bbSMiklos Szeredi unsigned int blkbits; 854203627bbSMiklos Szeredi 8551fb69e78SMiklos Szeredi stat->dev = inode->i_sb->s_dev; 8561fb69e78SMiklos Szeredi stat->ino = attr->ino; 8571fb69e78SMiklos Szeredi stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); 8581fb69e78SMiklos Szeredi stat->nlink = attr->nlink; 859499dcf20SEric W. Biederman stat->uid = make_kuid(&init_user_ns, attr->uid); 860499dcf20SEric W. Biederman stat->gid = make_kgid(&init_user_ns, attr->gid); 8611fb69e78SMiklos Szeredi stat->rdev = inode->i_rdev; 8621fb69e78SMiklos Szeredi stat->atime.tv_sec = attr->atime; 8631fb69e78SMiklos Szeredi stat->atime.tv_nsec = attr->atimensec; 8641fb69e78SMiklos Szeredi stat->mtime.tv_sec = attr->mtime; 8651fb69e78SMiklos Szeredi stat->mtime.tv_nsec = attr->mtimensec; 8661fb69e78SMiklos Szeredi stat->ctime.tv_sec = attr->ctime; 8671fb69e78SMiklos Szeredi stat->ctime.tv_nsec = attr->ctimensec; 8681fb69e78SMiklos Szeredi stat->size = attr->size; 8691fb69e78SMiklos Szeredi stat->blocks = attr->blocks; 870203627bbSMiklos Szeredi 871203627bbSMiklos Szeredi if (attr->blksize != 0) 872203627bbSMiklos Szeredi blkbits = ilog2(attr->blksize); 873203627bbSMiklos Szeredi else 874203627bbSMiklos Szeredi blkbits = inode->i_sb->s_blocksize_bits; 875203627bbSMiklos Szeredi 876203627bbSMiklos Szeredi stat->blksize = 1 << blkbits; 8771fb69e78SMiklos Szeredi } 8781fb69e78SMiklos Szeredi 879c79e322fSMiklos Szeredi static int fuse_do_getattr(struct inode *inode, struct kstat *stat, 880c79e322fSMiklos Szeredi struct file *file) 881e5e5558eSMiklos Szeredi { 882e5e5558eSMiklos Szeredi int err; 883c79e322fSMiklos Szeredi struct fuse_getattr_in inarg; 884c79e322fSMiklos Szeredi struct fuse_attr_out outarg; 885e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 8861fb69e78SMiklos Szeredi struct fuse_req *req; 8871fb69e78SMiklos Szeredi u64 attr_version; 8881fb69e78SMiklos Szeredi 889b111c8c0SMaxim Patlasov req = fuse_get_req_nopages(fc); 890ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 891ce1d5a49SMiklos Szeredi return PTR_ERR(req); 892e5e5558eSMiklos Szeredi 8937dca9fd3SMiklos Szeredi attr_version = fuse_get_attr_version(fc); 8941fb69e78SMiklos Szeredi 895c79e322fSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 8960e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 897c79e322fSMiklos Szeredi /* Directories have separate file-handle space */ 898c79e322fSMiklos Szeredi if (file && S_ISREG(inode->i_mode)) { 899c79e322fSMiklos Szeredi struct fuse_file *ff = file->private_data; 900c79e322fSMiklos Szeredi 901c79e322fSMiklos Szeredi inarg.getattr_flags |= FUSE_GETATTR_FH; 902c79e322fSMiklos Szeredi inarg.fh = ff->fh; 903c79e322fSMiklos Szeredi } 904e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_GETATTR; 905e5e5558eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 906c79e322fSMiklos Szeredi req->in.numargs = 1; 907c79e322fSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 908c79e322fSMiklos Szeredi req->in.args[0].value = &inarg; 909e5e5558eSMiklos Szeredi req->out.numargs = 1; 9100e9663eeSMiklos Szeredi if (fc->minor < 9) 9110e9663eeSMiklos Szeredi req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; 9120e9663eeSMiklos Szeredi else 913c79e322fSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 914c79e322fSMiklos Szeredi req->out.args[0].value = &outarg; 915b93f858aSTejun Heo fuse_request_send(fc, req); 916e5e5558eSMiklos Szeredi err = req->out.h.error; 917e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 918e5e5558eSMiklos Szeredi if (!err) { 919c79e322fSMiklos Szeredi if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { 920e5e5558eSMiklos Szeredi make_bad_inode(inode); 921e5e5558eSMiklos Szeredi err = -EIO; 922e5e5558eSMiklos Szeredi } else { 923c79e322fSMiklos Szeredi fuse_change_attributes(inode, &outarg.attr, 924c79e322fSMiklos Szeredi attr_timeout(&outarg), 9251fb69e78SMiklos Szeredi attr_version); 9261fb69e78SMiklos Szeredi if (stat) 927c79e322fSMiklos Szeredi fuse_fillattr(inode, &outarg.attr, stat); 928e5e5558eSMiklos Szeredi } 929e5e5558eSMiklos Szeredi } 930e5e5558eSMiklos Szeredi return err; 931e5e5558eSMiklos Szeredi } 932e5e5558eSMiklos Szeredi 933bcb4be80SMiklos Szeredi int fuse_update_attributes(struct inode *inode, struct kstat *stat, 934bcb4be80SMiklos Szeredi struct file *file, bool *refreshed) 935bcb4be80SMiklos Szeredi { 936bcb4be80SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 937bcb4be80SMiklos Szeredi int err; 938bcb4be80SMiklos Szeredi bool r; 939bcb4be80SMiklos Szeredi 940bcb4be80SMiklos Szeredi if (fi->i_time < get_jiffies_64()) { 941bcb4be80SMiklos Szeredi r = true; 942bcb4be80SMiklos Szeredi err = fuse_do_getattr(inode, stat, file); 943bcb4be80SMiklos Szeredi } else { 944bcb4be80SMiklos Szeredi r = false; 945bcb4be80SMiklos Szeredi err = 0; 946bcb4be80SMiklos Szeredi if (stat) { 947bcb4be80SMiklos Szeredi generic_fillattr(inode, stat); 948bcb4be80SMiklos Szeredi stat->mode = fi->orig_i_mode; 94945c72cd7SPavel Shilovsky stat->ino = fi->orig_ino; 950bcb4be80SMiklos Szeredi } 951bcb4be80SMiklos Szeredi } 952bcb4be80SMiklos Szeredi 953bcb4be80SMiklos Szeredi if (refreshed != NULL) 954bcb4be80SMiklos Szeredi *refreshed = r; 955bcb4be80SMiklos Szeredi 956bcb4be80SMiklos Szeredi return err; 957bcb4be80SMiklos Szeredi } 958bcb4be80SMiklos Szeredi 9593b463ae0SJohn Muir int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, 960451d0f59SJohn Muir u64 child_nodeid, struct qstr *name) 9613b463ae0SJohn Muir { 9623b463ae0SJohn Muir int err = -ENOTDIR; 9633b463ae0SJohn Muir struct inode *parent; 9643b463ae0SJohn Muir struct dentry *dir; 9653b463ae0SJohn Muir struct dentry *entry; 9663b463ae0SJohn Muir 9673b463ae0SJohn Muir parent = ilookup5(sb, parent_nodeid, fuse_inode_eq, &parent_nodeid); 9683b463ae0SJohn Muir if (!parent) 9693b463ae0SJohn Muir return -ENOENT; 9703b463ae0SJohn Muir 9713b463ae0SJohn Muir mutex_lock(&parent->i_mutex); 9723b463ae0SJohn Muir if (!S_ISDIR(parent->i_mode)) 9733b463ae0SJohn Muir goto unlock; 9743b463ae0SJohn Muir 9753b463ae0SJohn Muir err = -ENOENT; 9763b463ae0SJohn Muir dir = d_find_alias(parent); 9773b463ae0SJohn Muir if (!dir) 9783b463ae0SJohn Muir goto unlock; 9793b463ae0SJohn Muir 9803b463ae0SJohn Muir entry = d_lookup(dir, name); 9813b463ae0SJohn Muir dput(dir); 9823b463ae0SJohn Muir if (!entry) 9833b463ae0SJohn Muir goto unlock; 9843b463ae0SJohn Muir 9853b463ae0SJohn Muir fuse_invalidate_attr(parent); 9863b463ae0SJohn Muir fuse_invalidate_entry(entry); 987451d0f59SJohn Muir 988451d0f59SJohn Muir if (child_nodeid != 0 && entry->d_inode) { 989451d0f59SJohn Muir mutex_lock(&entry->d_inode->i_mutex); 990451d0f59SJohn Muir if (get_node_id(entry->d_inode) != child_nodeid) { 991451d0f59SJohn Muir err = -ENOENT; 992451d0f59SJohn Muir goto badentry; 993451d0f59SJohn Muir } 994451d0f59SJohn Muir if (d_mountpoint(entry)) { 995451d0f59SJohn Muir err = -EBUSY; 996451d0f59SJohn Muir goto badentry; 997451d0f59SJohn Muir } 998451d0f59SJohn Muir if (S_ISDIR(entry->d_inode->i_mode)) { 999451d0f59SJohn Muir shrink_dcache_parent(entry); 1000451d0f59SJohn Muir if (!simple_empty(entry)) { 1001451d0f59SJohn Muir err = -ENOTEMPTY; 1002451d0f59SJohn Muir goto badentry; 1003451d0f59SJohn Muir } 1004451d0f59SJohn Muir entry->d_inode->i_flags |= S_DEAD; 1005451d0f59SJohn Muir } 1006451d0f59SJohn Muir dont_mount(entry); 1007451d0f59SJohn Muir clear_nlink(entry->d_inode); 10083b463ae0SJohn Muir err = 0; 1009451d0f59SJohn Muir badentry: 1010451d0f59SJohn Muir mutex_unlock(&entry->d_inode->i_mutex); 1011451d0f59SJohn Muir if (!err) 1012451d0f59SJohn Muir d_delete(entry); 1013451d0f59SJohn Muir } else { 1014451d0f59SJohn Muir err = 0; 1015451d0f59SJohn Muir } 1016451d0f59SJohn Muir dput(entry); 10173b463ae0SJohn Muir 10183b463ae0SJohn Muir unlock: 10193b463ae0SJohn Muir mutex_unlock(&parent->i_mutex); 10203b463ae0SJohn Muir iput(parent); 10213b463ae0SJohn Muir return err; 10223b463ae0SJohn Muir } 10233b463ae0SJohn Muir 102487729a55SMiklos Szeredi /* 102587729a55SMiklos Szeredi * Calling into a user-controlled filesystem gives the filesystem 1026c2132c1bSAnatol Pomozov * daemon ptrace-like capabilities over the current process. This 102787729a55SMiklos Szeredi * means, that the filesystem daemon is able to record the exact 102887729a55SMiklos Szeredi * filesystem operations performed, and can also control the behavior 102987729a55SMiklos Szeredi * of the requester process in otherwise impossible ways. For example 103087729a55SMiklos Szeredi * it can delay the operation for arbitrary length of time allowing 103187729a55SMiklos Szeredi * DoS against the requester. 103287729a55SMiklos Szeredi * 103387729a55SMiklos Szeredi * For this reason only those processes can call into the filesystem, 103487729a55SMiklos Szeredi * for which the owner of the mount has ptrace privilege. This 103587729a55SMiklos Szeredi * excludes processes started by other users, suid or sgid processes. 103687729a55SMiklos Szeredi */ 1037c2132c1bSAnatol Pomozov int fuse_allow_current_process(struct fuse_conn *fc) 103887729a55SMiklos Szeredi { 1039c69e8d9cSDavid Howells const struct cred *cred; 1040c69e8d9cSDavid Howells 104187729a55SMiklos Szeredi if (fc->flags & FUSE_ALLOW_OTHER) 104287729a55SMiklos Szeredi return 1; 104387729a55SMiklos Szeredi 1044c2132c1bSAnatol Pomozov cred = current_cred(); 1045499dcf20SEric W. Biederman if (uid_eq(cred->euid, fc->user_id) && 1046499dcf20SEric W. Biederman uid_eq(cred->suid, fc->user_id) && 1047499dcf20SEric W. Biederman uid_eq(cred->uid, fc->user_id) && 1048499dcf20SEric W. Biederman gid_eq(cred->egid, fc->group_id) && 1049499dcf20SEric W. Biederman gid_eq(cred->sgid, fc->group_id) && 1050499dcf20SEric W. Biederman gid_eq(cred->gid, fc->group_id)) 1051c2132c1bSAnatol Pomozov return 1; 105287729a55SMiklos Szeredi 1053c2132c1bSAnatol Pomozov return 0; 105487729a55SMiklos Szeredi } 105587729a55SMiklos Szeredi 105631d40d74SMiklos Szeredi static int fuse_access(struct inode *inode, int mask) 105731d40d74SMiklos Szeredi { 105831d40d74SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 105931d40d74SMiklos Szeredi struct fuse_req *req; 106031d40d74SMiklos Szeredi struct fuse_access_in inarg; 106131d40d74SMiklos Szeredi int err; 106231d40d74SMiklos Szeredi 106331d40d74SMiklos Szeredi if (fc->no_access) 106431d40d74SMiklos Szeredi return 0; 106531d40d74SMiklos Szeredi 1066b111c8c0SMaxim Patlasov req = fuse_get_req_nopages(fc); 1067ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1068ce1d5a49SMiklos Szeredi return PTR_ERR(req); 106931d40d74SMiklos Szeredi 107031d40d74SMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 1071e6305c43SAl Viro inarg.mask = mask & (MAY_READ | MAY_WRITE | MAY_EXEC); 107231d40d74SMiklos Szeredi req->in.h.opcode = FUSE_ACCESS; 107331d40d74SMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 107431d40d74SMiklos Szeredi req->in.numargs = 1; 107531d40d74SMiklos Szeredi req->in.args[0].size = sizeof(inarg); 107631d40d74SMiklos Szeredi req->in.args[0].value = &inarg; 1077b93f858aSTejun Heo fuse_request_send(fc, req); 107831d40d74SMiklos Szeredi err = req->out.h.error; 107931d40d74SMiklos Szeredi fuse_put_request(fc, req); 108031d40d74SMiklos Szeredi if (err == -ENOSYS) { 108131d40d74SMiklos Szeredi fc->no_access = 1; 108231d40d74SMiklos Szeredi err = 0; 108331d40d74SMiklos Szeredi } 108431d40d74SMiklos Szeredi return err; 108531d40d74SMiklos Szeredi } 108631d40d74SMiklos Szeredi 108710556cb2SAl Viro static int fuse_perm_getattr(struct inode *inode, int mask) 108819690ddbSMiklos Szeredi { 108910556cb2SAl Viro if (mask & MAY_NOT_BLOCK) 109019690ddbSMiklos Szeredi return -ECHILD; 109119690ddbSMiklos Szeredi 109219690ddbSMiklos Szeredi return fuse_do_getattr(inode, NULL, NULL); 109319690ddbSMiklos Szeredi } 109419690ddbSMiklos Szeredi 10956f9f1180SMiklos Szeredi /* 10966f9f1180SMiklos Szeredi * Check permission. The two basic access models of FUSE are: 10976f9f1180SMiklos Szeredi * 10986f9f1180SMiklos Szeredi * 1) Local access checking ('default_permissions' mount option) based 10996f9f1180SMiklos Szeredi * on file mode. This is the plain old disk filesystem permission 11006f9f1180SMiklos Szeredi * modell. 11016f9f1180SMiklos Szeredi * 11026f9f1180SMiklos Szeredi * 2) "Remote" access checking, where server is responsible for 11036f9f1180SMiklos Szeredi * checking permission in each inode operation. An exception to this 11046f9f1180SMiklos Szeredi * is if ->permission() was invoked from sys_access() in which case an 11056f9f1180SMiklos Szeredi * access request is sent. Execute permission is still checked 11066f9f1180SMiklos Szeredi * locally based on file mode. 11076f9f1180SMiklos Szeredi */ 110810556cb2SAl Viro static int fuse_permission(struct inode *inode, int mask) 1109e5e5558eSMiklos Szeredi { 1110e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1111244f6385SMiklos Szeredi bool refreshed = false; 1112244f6385SMiklos Szeredi int err = 0; 1113e5e5558eSMiklos Szeredi 1114c2132c1bSAnatol Pomozov if (!fuse_allow_current_process(fc)) 1115e5e5558eSMiklos Szeredi return -EACCES; 1116244f6385SMiklos Szeredi 1117244f6385SMiklos Szeredi /* 1118e8e96157SMiklos Szeredi * If attributes are needed, refresh them before proceeding 1119244f6385SMiklos Szeredi */ 1120e8e96157SMiklos Szeredi if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) || 1121e8e96157SMiklos Szeredi ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { 112219690ddbSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 112319690ddbSMiklos Szeredi 112419690ddbSMiklos Szeredi if (fi->i_time < get_jiffies_64()) { 112519690ddbSMiklos Szeredi refreshed = true; 112619690ddbSMiklos Szeredi 112710556cb2SAl Viro err = fuse_perm_getattr(inode, mask); 1128244f6385SMiklos Szeredi if (err) 1129244f6385SMiklos Szeredi return err; 11301fb69e78SMiklos Szeredi } 113119690ddbSMiklos Szeredi } 1132244f6385SMiklos Szeredi 1133244f6385SMiklos Szeredi if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 11342830ba7fSAl Viro err = generic_permission(inode, mask); 11351e9a4ed9SMiklos Szeredi 11361e9a4ed9SMiklos Szeredi /* If permission is denied, try to refresh file 11371e9a4ed9SMiklos Szeredi attributes. This is also needed, because the root 11381e9a4ed9SMiklos Szeredi node will at first have no permissions */ 1139244f6385SMiklos Szeredi if (err == -EACCES && !refreshed) { 114010556cb2SAl Viro err = fuse_perm_getattr(inode, mask); 11411e9a4ed9SMiklos Szeredi if (!err) 11422830ba7fSAl Viro err = generic_permission(inode, mask); 11431e9a4ed9SMiklos Szeredi } 11441e9a4ed9SMiklos Szeredi 11456f9f1180SMiklos Szeredi /* Note: the opposite of the above test does not 11466f9f1180SMiklos Szeredi exist. So if permissions are revoked this won't be 11476f9f1180SMiklos Szeredi noticed immediately, only after the attribute 11486f9f1180SMiklos Szeredi timeout has expired */ 11499cfcac81SEric Paris } else if (mask & (MAY_ACCESS | MAY_CHDIR)) { 115010556cb2SAl Viro if (mask & MAY_NOT_BLOCK) 115119690ddbSMiklos Szeredi return -ECHILD; 115219690ddbSMiklos Szeredi 1153e8e96157SMiklos Szeredi err = fuse_access(inode, mask); 1154e8e96157SMiklos Szeredi } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { 1155e8e96157SMiklos Szeredi if (!(inode->i_mode & S_IXUGO)) { 1156e8e96157SMiklos Szeredi if (refreshed) 1157e5e5558eSMiklos Szeredi return -EACCES; 115831d40d74SMiklos Szeredi 115910556cb2SAl Viro err = fuse_perm_getattr(inode, mask); 1160e8e96157SMiklos Szeredi if (!err && !(inode->i_mode & S_IXUGO)) 1161e8e96157SMiklos Szeredi return -EACCES; 1162e8e96157SMiklos Szeredi } 1163e5e5558eSMiklos Szeredi } 1164244f6385SMiklos Szeredi return err; 1165e5e5558eSMiklos Szeredi } 1166e5e5558eSMiklos Szeredi 1167e5e5558eSMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file, 1168e5e5558eSMiklos Szeredi void *dstbuf, filldir_t filldir) 1169e5e5558eSMiklos Szeredi { 1170e5e5558eSMiklos Szeredi while (nbytes >= FUSE_NAME_OFFSET) { 1171e5e5558eSMiklos Szeredi struct fuse_dirent *dirent = (struct fuse_dirent *) buf; 1172e5e5558eSMiklos Szeredi size_t reclen = FUSE_DIRENT_SIZE(dirent); 1173e5e5558eSMiklos Szeredi int over; 1174e5e5558eSMiklos Szeredi if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) 1175e5e5558eSMiklos Szeredi return -EIO; 1176e5e5558eSMiklos Szeredi if (reclen > nbytes) 1177e5e5558eSMiklos Szeredi break; 1178e5e5558eSMiklos Szeredi 1179e5e5558eSMiklos Szeredi over = filldir(dstbuf, dirent->name, dirent->namelen, 1180e5e5558eSMiklos Szeredi file->f_pos, dirent->ino, dirent->type); 1181e5e5558eSMiklos Szeredi if (over) 1182e5e5558eSMiklos Szeredi break; 1183e5e5558eSMiklos Szeredi 1184e5e5558eSMiklos Szeredi buf += reclen; 1185e5e5558eSMiklos Szeredi nbytes -= reclen; 1186e5e5558eSMiklos Szeredi file->f_pos = dirent->off; 1187e5e5558eSMiklos Szeredi } 1188e5e5558eSMiklos Szeredi 1189e5e5558eSMiklos Szeredi return 0; 1190e5e5558eSMiklos Szeredi } 1191e5e5558eSMiklos Szeredi 11920b05b183SAnand V. Avati static int fuse_direntplus_link(struct file *file, 11930b05b183SAnand V. Avati struct fuse_direntplus *direntplus, 11940b05b183SAnand V. Avati u64 attr_version) 11950b05b183SAnand V. Avati { 11960b05b183SAnand V. Avati int err; 11970b05b183SAnand V. Avati struct fuse_entry_out *o = &direntplus->entry_out; 11980b05b183SAnand V. Avati struct fuse_dirent *dirent = &direntplus->dirent; 11990b05b183SAnand V. Avati struct dentry *parent = file->f_path.dentry; 12000b05b183SAnand V. Avati struct qstr name = QSTR_INIT(dirent->name, dirent->namelen); 12010b05b183SAnand V. Avati struct dentry *dentry; 12020b05b183SAnand V. Avati struct dentry *alias; 12030b05b183SAnand V. Avati struct inode *dir = parent->d_inode; 12040b05b183SAnand V. Avati struct fuse_conn *fc; 12050b05b183SAnand V. Avati struct inode *inode; 12060b05b183SAnand V. Avati 12070b05b183SAnand V. Avati if (!o->nodeid) { 12080b05b183SAnand V. Avati /* 12090b05b183SAnand V. Avati * Unlike in the case of fuse_lookup, zero nodeid does not mean 12100b05b183SAnand V. Avati * ENOENT. Instead, it only means the userspace filesystem did 12110b05b183SAnand V. Avati * not want to return attributes/handle for this entry. 12120b05b183SAnand V. Avati * 12130b05b183SAnand V. Avati * So do nothing. 12140b05b183SAnand V. Avati */ 12150b05b183SAnand V. Avati return 0; 12160b05b183SAnand V. Avati } 12170b05b183SAnand V. Avati 12180b05b183SAnand V. Avati if (name.name[0] == '.') { 12190b05b183SAnand V. Avati /* 12200b05b183SAnand V. Avati * We could potentially refresh the attributes of the directory 12210b05b183SAnand V. Avati * and its parent? 12220b05b183SAnand V. Avati */ 12230b05b183SAnand V. Avati if (name.len == 1) 12240b05b183SAnand V. Avati return 0; 12250b05b183SAnand V. Avati if (name.name[1] == '.' && name.len == 2) 12260b05b183SAnand V. Avati return 0; 12270b05b183SAnand V. Avati } 12280b05b183SAnand V. Avati fc = get_fuse_conn(dir); 12290b05b183SAnand V. Avati 12300b05b183SAnand V. Avati name.hash = full_name_hash(name.name, name.len); 12310b05b183SAnand V. Avati dentry = d_lookup(parent, &name); 12320b05b183SAnand V. Avati if (dentry && dentry->d_inode) { 12330b05b183SAnand V. Avati inode = dentry->d_inode; 12340b05b183SAnand V. Avati if (get_node_id(inode) == o->nodeid) { 12350b05b183SAnand V. Avati struct fuse_inode *fi; 12360b05b183SAnand V. Avati fi = get_fuse_inode(inode); 12370b05b183SAnand V. Avati spin_lock(&fc->lock); 12380b05b183SAnand V. Avati fi->nlookup++; 12390b05b183SAnand V. Avati spin_unlock(&fc->lock); 12400b05b183SAnand V. Avati 12410b05b183SAnand V. Avati /* 12420b05b183SAnand V. Avati * The other branch to 'found' comes via fuse_iget() 12430b05b183SAnand V. Avati * which bumps nlookup inside 12440b05b183SAnand V. Avati */ 12450b05b183SAnand V. Avati goto found; 12460b05b183SAnand V. Avati } 12470b05b183SAnand V. Avati err = d_invalidate(dentry); 12480b05b183SAnand V. Avati if (err) 12490b05b183SAnand V. Avati goto out; 12500b05b183SAnand V. Avati dput(dentry); 12510b05b183SAnand V. Avati dentry = NULL; 12520b05b183SAnand V. Avati } 12530b05b183SAnand V. Avati 12540b05b183SAnand V. Avati dentry = d_alloc(parent, &name); 12550b05b183SAnand V. Avati err = -ENOMEM; 12560b05b183SAnand V. Avati if (!dentry) 12570b05b183SAnand V. Avati goto out; 12580b05b183SAnand V. Avati 12590b05b183SAnand V. Avati inode = fuse_iget(dir->i_sb, o->nodeid, o->generation, 12600b05b183SAnand V. Avati &o->attr, entry_attr_timeout(o), attr_version); 12610b05b183SAnand V. Avati if (!inode) 12620b05b183SAnand V. Avati goto out; 12630b05b183SAnand V. Avati 12640b05b183SAnand V. Avati alias = d_materialise_unique(dentry, inode); 12650b05b183SAnand V. Avati err = PTR_ERR(alias); 12660b05b183SAnand V. Avati if (IS_ERR(alias)) 12670b05b183SAnand V. Avati goto out; 12680b05b183SAnand V. Avati if (alias) { 12690b05b183SAnand V. Avati dput(dentry); 12700b05b183SAnand V. Avati dentry = alias; 12710b05b183SAnand V. Avati } 12720b05b183SAnand V. Avati 12730b05b183SAnand V. Avati found: 12740b05b183SAnand V. Avati fuse_change_attributes(inode, &o->attr, entry_attr_timeout(o), 12750b05b183SAnand V. Avati attr_version); 12760b05b183SAnand V. Avati 12770b05b183SAnand V. Avati fuse_change_entry_timeout(dentry, o); 12780b05b183SAnand V. Avati 12790b05b183SAnand V. Avati err = 0; 12800b05b183SAnand V. Avati out: 12810b05b183SAnand V. Avati if (dentry) 12820b05b183SAnand V. Avati dput(dentry); 12830b05b183SAnand V. Avati return err; 12840b05b183SAnand V. Avati } 12850b05b183SAnand V. Avati 12860b05b183SAnand V. Avati static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file, 12870b05b183SAnand V. Avati void *dstbuf, filldir_t filldir, u64 attr_version) 12880b05b183SAnand V. Avati { 12890b05b183SAnand V. Avati struct fuse_direntplus *direntplus; 12900b05b183SAnand V. Avati struct fuse_dirent *dirent; 12910b05b183SAnand V. Avati size_t reclen; 12920b05b183SAnand V. Avati int over = 0; 12930b05b183SAnand V. Avati int ret; 12940b05b183SAnand V. Avati 12950b05b183SAnand V. Avati while (nbytes >= FUSE_NAME_OFFSET_DIRENTPLUS) { 12960b05b183SAnand V. Avati direntplus = (struct fuse_direntplus *) buf; 12970b05b183SAnand V. Avati dirent = &direntplus->dirent; 12980b05b183SAnand V. Avati reclen = FUSE_DIRENTPLUS_SIZE(direntplus); 12990b05b183SAnand V. Avati 13000b05b183SAnand V. Avati if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) 13010b05b183SAnand V. Avati return -EIO; 13020b05b183SAnand V. Avati if (reclen > nbytes) 13030b05b183SAnand V. Avati break; 13040b05b183SAnand V. Avati 13050b05b183SAnand V. Avati if (!over) { 13060b05b183SAnand V. Avati /* We fill entries into dstbuf only as much as 13070b05b183SAnand V. Avati it can hold. But we still continue iterating 13080b05b183SAnand V. Avati over remaining entries to link them. If not, 13090b05b183SAnand V. Avati we need to send a FORGET for each of those 13100b05b183SAnand V. Avati which we did not link. 13110b05b183SAnand V. Avati */ 13120b05b183SAnand V. Avati over = filldir(dstbuf, dirent->name, dirent->namelen, 13130b05b183SAnand V. Avati file->f_pos, dirent->ino, 13140b05b183SAnand V. Avati dirent->type); 13150b05b183SAnand V. Avati file->f_pos = dirent->off; 13160b05b183SAnand V. Avati } 13170b05b183SAnand V. Avati 13180b05b183SAnand V. Avati buf += reclen; 13190b05b183SAnand V. Avati nbytes -= reclen; 13200b05b183SAnand V. Avati 13210b05b183SAnand V. Avati ret = fuse_direntplus_link(file, direntplus, attr_version); 13220b05b183SAnand V. Avati if (ret) 13230b05b183SAnand V. Avati fuse_force_forget(file, direntplus->entry_out.nodeid); 13240b05b183SAnand V. Avati } 13250b05b183SAnand V. Avati 13260b05b183SAnand V. Avati return 0; 13270b05b183SAnand V. Avati } 13280b05b183SAnand V. Avati 1329e5e5558eSMiklos Szeredi static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) 1330e5e5558eSMiklos Szeredi { 13314582a4abSFeng Shuo int plus, err; 133204730fefSMiklos Szeredi size_t nbytes; 133304730fefSMiklos Szeredi struct page *page; 1334496ad9aaSAl Viro struct inode *inode = file_inode(file); 133504730fefSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1336248d86e8SMiklos Szeredi struct fuse_req *req; 13370b05b183SAnand V. Avati u64 attr_version = 0; 1338248d86e8SMiklos Szeredi 1339248d86e8SMiklos Szeredi if (is_bad_inode(inode)) 1340248d86e8SMiklos Szeredi return -EIO; 1341248d86e8SMiklos Szeredi 1342b111c8c0SMaxim Patlasov req = fuse_get_req(fc, 1); 1343ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1344ce1d5a49SMiklos Szeredi return PTR_ERR(req); 1345e5e5558eSMiklos Szeredi 134604730fefSMiklos Szeredi page = alloc_page(GFP_KERNEL); 134704730fefSMiklos Szeredi if (!page) { 134804730fefSMiklos Szeredi fuse_put_request(fc, req); 1349e5e5558eSMiklos Szeredi return -ENOMEM; 135004730fefSMiklos Szeredi } 13514582a4abSFeng Shuo 13524582a4abSFeng Shuo plus = fuse_use_readdirplus(inode, file); 1353f4975c67SMiklos Szeredi req->out.argpages = 1; 135404730fefSMiklos Szeredi req->num_pages = 1; 135504730fefSMiklos Szeredi req->pages[0] = page; 135685f40aecSMaxim Patlasov req->page_descs[0].length = PAGE_SIZE; 13574582a4abSFeng Shuo if (plus) { 13580b05b183SAnand V. Avati attr_version = fuse_get_attr_version(fc); 13590b05b183SAnand V. Avati fuse_read_fill(req, file, file->f_pos, PAGE_SIZE, 13600b05b183SAnand V. Avati FUSE_READDIRPLUS); 13610b05b183SAnand V. Avati } else { 13620b05b183SAnand V. Avati fuse_read_fill(req, file, file->f_pos, PAGE_SIZE, 13630b05b183SAnand V. Avati FUSE_READDIR); 13640b05b183SAnand V. Avati } 1365b93f858aSTejun Heo fuse_request_send(fc, req); 1366361b1eb5SMiklos Szeredi nbytes = req->out.args[0].size; 136704730fefSMiklos Szeredi err = req->out.h.error; 136804730fefSMiklos Szeredi fuse_put_request(fc, req); 13690b05b183SAnand V. Avati if (!err) { 13704582a4abSFeng Shuo if (plus) { 13710b05b183SAnand V. Avati err = parse_dirplusfile(page_address(page), nbytes, 13720b05b183SAnand V. Avati file, dstbuf, filldir, 13730b05b183SAnand V. Avati attr_version); 13740b05b183SAnand V. Avati } else { 13750b05b183SAnand V. Avati err = parse_dirfile(page_address(page), nbytes, file, 13760b05b183SAnand V. Avati dstbuf, filldir); 13770b05b183SAnand V. Avati } 13780b05b183SAnand V. Avati } 1379e5e5558eSMiklos Szeredi 138004730fefSMiklos Szeredi __free_page(page); 1381b36c31baSMiklos Szeredi fuse_invalidate_attr(inode); /* atime changed */ 138204730fefSMiklos Szeredi return err; 1383e5e5558eSMiklos Szeredi } 1384e5e5558eSMiklos Szeredi 1385e5e5558eSMiklos Szeredi static char *read_link(struct dentry *dentry) 1386e5e5558eSMiklos Szeredi { 1387e5e5558eSMiklos Szeredi struct inode *inode = dentry->d_inode; 1388e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1389b111c8c0SMaxim Patlasov struct fuse_req *req = fuse_get_req_nopages(fc); 1390e5e5558eSMiklos Szeredi char *link; 1391e5e5558eSMiklos Szeredi 1392ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1393e231c2eeSDavid Howells return ERR_CAST(req); 1394e5e5558eSMiklos Szeredi 1395e5e5558eSMiklos Szeredi link = (char *) __get_free_page(GFP_KERNEL); 1396e5e5558eSMiklos Szeredi if (!link) { 1397e5e5558eSMiklos Szeredi link = ERR_PTR(-ENOMEM); 1398e5e5558eSMiklos Szeredi goto out; 1399e5e5558eSMiklos Szeredi } 1400e5e5558eSMiklos Szeredi req->in.h.opcode = FUSE_READLINK; 1401e5e5558eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 1402e5e5558eSMiklos Szeredi req->out.argvar = 1; 1403e5e5558eSMiklos Szeredi req->out.numargs = 1; 1404e5e5558eSMiklos Szeredi req->out.args[0].size = PAGE_SIZE - 1; 1405e5e5558eSMiklos Szeredi req->out.args[0].value = link; 1406b93f858aSTejun Heo fuse_request_send(fc, req); 1407e5e5558eSMiklos Szeredi if (req->out.h.error) { 1408e5e5558eSMiklos Szeredi free_page((unsigned long) link); 1409e5e5558eSMiklos Szeredi link = ERR_PTR(req->out.h.error); 1410e5e5558eSMiklos Szeredi } else 1411e5e5558eSMiklos Szeredi link[req->out.args[0].size] = '\0'; 1412e5e5558eSMiklos Szeredi out: 1413e5e5558eSMiklos Szeredi fuse_put_request(fc, req); 1414b36c31baSMiklos Szeredi fuse_invalidate_attr(inode); /* atime changed */ 1415e5e5558eSMiklos Szeredi return link; 1416e5e5558eSMiklos Szeredi } 1417e5e5558eSMiklos Szeredi 1418e5e5558eSMiklos Szeredi static void free_link(char *link) 1419e5e5558eSMiklos Szeredi { 1420e5e5558eSMiklos Szeredi if (!IS_ERR(link)) 1421e5e5558eSMiklos Szeredi free_page((unsigned long) link); 1422e5e5558eSMiklos Szeredi } 1423e5e5558eSMiklos Szeredi 1424e5e5558eSMiklos Szeredi static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd) 1425e5e5558eSMiklos Szeredi { 1426e5e5558eSMiklos Szeredi nd_set_link(nd, read_link(dentry)); 1427e5e5558eSMiklos Szeredi return NULL; 1428e5e5558eSMiklos Szeredi } 1429e5e5558eSMiklos Szeredi 1430e5e5558eSMiklos Szeredi static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c) 1431e5e5558eSMiklos Szeredi { 1432e5e5558eSMiklos Szeredi free_link(nd_get_link(nd)); 1433e5e5558eSMiklos Szeredi } 1434e5e5558eSMiklos Szeredi 1435e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file) 1436e5e5558eSMiklos Szeredi { 143791fe96b4SMiklos Szeredi return fuse_open_common(inode, file, true); 1438e5e5558eSMiklos Szeredi } 1439e5e5558eSMiklos Szeredi 1440e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file) 1441e5e5558eSMiklos Szeredi { 14428b0797a4SMiklos Szeredi fuse_release_common(file, FUSE_RELEASEDIR); 14438b0797a4SMiklos Szeredi 14448b0797a4SMiklos Szeredi return 0; 1445e5e5558eSMiklos Szeredi } 1446e5e5558eSMiklos Szeredi 144702c24a82SJosef Bacik static int fuse_dir_fsync(struct file *file, loff_t start, loff_t end, 144802c24a82SJosef Bacik int datasync) 144982547981SMiklos Szeredi { 145002c24a82SJosef Bacik return fuse_fsync_common(file, start, end, datasync, 1); 145182547981SMiklos Szeredi } 145282547981SMiklos Szeredi 1453b18da0c5SMiklos Szeredi static long fuse_dir_ioctl(struct file *file, unsigned int cmd, 1454b18da0c5SMiklos Szeredi unsigned long arg) 1455b18da0c5SMiklos Szeredi { 1456b18da0c5SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(file->f_mapping->host); 1457b18da0c5SMiklos Szeredi 1458b18da0c5SMiklos Szeredi /* FUSE_IOCTL_DIR only supported for API version >= 7.18 */ 1459b18da0c5SMiklos Szeredi if (fc->minor < 18) 1460b18da0c5SMiklos Szeredi return -ENOTTY; 1461b18da0c5SMiklos Szeredi 1462b18da0c5SMiklos Szeredi return fuse_ioctl_common(file, cmd, arg, FUSE_IOCTL_DIR); 1463b18da0c5SMiklos Szeredi } 1464b18da0c5SMiklos Szeredi 1465b18da0c5SMiklos Szeredi static long fuse_dir_compat_ioctl(struct file *file, unsigned int cmd, 1466b18da0c5SMiklos Szeredi unsigned long arg) 1467b18da0c5SMiklos Szeredi { 1468b18da0c5SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(file->f_mapping->host); 1469b18da0c5SMiklos Szeredi 1470b18da0c5SMiklos Szeredi if (fc->minor < 18) 1471b18da0c5SMiklos Szeredi return -ENOTTY; 1472b18da0c5SMiklos Szeredi 1473b18da0c5SMiklos Szeredi return fuse_ioctl_common(file, cmd, arg, 1474b18da0c5SMiklos Szeredi FUSE_IOCTL_COMPAT | FUSE_IOCTL_DIR); 1475b18da0c5SMiklos Szeredi } 1476b18da0c5SMiklos Szeredi 147717637cbaSMiklos Szeredi static bool update_mtime(unsigned ivalid) 147817637cbaSMiklos Szeredi { 147917637cbaSMiklos Szeredi /* Always update if mtime is explicitly set */ 148017637cbaSMiklos Szeredi if (ivalid & ATTR_MTIME_SET) 148117637cbaSMiklos Szeredi return true; 148217637cbaSMiklos Szeredi 148317637cbaSMiklos Szeredi /* If it's an open(O_TRUNC) or an ftruncate(), don't update */ 148417637cbaSMiklos Szeredi if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE))) 148517637cbaSMiklos Szeredi return false; 148617637cbaSMiklos Szeredi 148717637cbaSMiklos Szeredi /* In all other cases update */ 148817637cbaSMiklos Szeredi return true; 148917637cbaSMiklos Szeredi } 149017637cbaSMiklos Szeredi 1491befc649cSMiklos Szeredi static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) 14929e6268dbSMiklos Szeredi { 14939e6268dbSMiklos Szeredi unsigned ivalid = iattr->ia_valid; 14949e6268dbSMiklos Szeredi 14959e6268dbSMiklos Szeredi if (ivalid & ATTR_MODE) 1496befc649cSMiklos Szeredi arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode; 14979e6268dbSMiklos Szeredi if (ivalid & ATTR_UID) 1498499dcf20SEric W. Biederman arg->valid |= FATTR_UID, arg->uid = from_kuid(&init_user_ns, iattr->ia_uid); 14999e6268dbSMiklos Szeredi if (ivalid & ATTR_GID) 1500499dcf20SEric W. Biederman arg->valid |= FATTR_GID, arg->gid = from_kgid(&init_user_ns, iattr->ia_gid); 15019e6268dbSMiklos Szeredi if (ivalid & ATTR_SIZE) 1502befc649cSMiklos Szeredi arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size; 150317637cbaSMiklos Szeredi if (ivalid & ATTR_ATIME) { 150417637cbaSMiklos Szeredi arg->valid |= FATTR_ATIME; 1505befc649cSMiklos Szeredi arg->atime = iattr->ia_atime.tv_sec; 150617637cbaSMiklos Szeredi arg->atimensec = iattr->ia_atime.tv_nsec; 150717637cbaSMiklos Szeredi if (!(ivalid & ATTR_ATIME_SET)) 150817637cbaSMiklos Szeredi arg->valid |= FATTR_ATIME_NOW; 150917637cbaSMiklos Szeredi } 151017637cbaSMiklos Szeredi if ((ivalid & ATTR_MTIME) && update_mtime(ivalid)) { 151117637cbaSMiklos Szeredi arg->valid |= FATTR_MTIME; 1512befc649cSMiklos Szeredi arg->mtime = iattr->ia_mtime.tv_sec; 151317637cbaSMiklos Szeredi arg->mtimensec = iattr->ia_mtime.tv_nsec; 151417637cbaSMiklos Szeredi if (!(ivalid & ATTR_MTIME_SET)) 151517637cbaSMiklos Szeredi arg->valid |= FATTR_MTIME_NOW; 15169e6268dbSMiklos Szeredi } 15179e6268dbSMiklos Szeredi } 15189e6268dbSMiklos Szeredi 15196f9f1180SMiklos Szeredi /* 15203be5a52bSMiklos Szeredi * Prevent concurrent writepages on inode 15213be5a52bSMiklos Szeredi * 15223be5a52bSMiklos Szeredi * This is done by adding a negative bias to the inode write counter 15233be5a52bSMiklos Szeredi * and waiting for all pending writes to finish. 15243be5a52bSMiklos Szeredi */ 15253be5a52bSMiklos Szeredi void fuse_set_nowrite(struct inode *inode) 15263be5a52bSMiklos Szeredi { 15273be5a52bSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 15283be5a52bSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 15293be5a52bSMiklos Szeredi 15303be5a52bSMiklos Szeredi BUG_ON(!mutex_is_locked(&inode->i_mutex)); 15313be5a52bSMiklos Szeredi 15323be5a52bSMiklos Szeredi spin_lock(&fc->lock); 15333be5a52bSMiklos Szeredi BUG_ON(fi->writectr < 0); 15343be5a52bSMiklos Szeredi fi->writectr += FUSE_NOWRITE; 15353be5a52bSMiklos Szeredi spin_unlock(&fc->lock); 15363be5a52bSMiklos Szeredi wait_event(fi->page_waitq, fi->writectr == FUSE_NOWRITE); 15373be5a52bSMiklos Szeredi } 15383be5a52bSMiklos Szeredi 15393be5a52bSMiklos Szeredi /* 15403be5a52bSMiklos Szeredi * Allow writepages on inode 15413be5a52bSMiklos Szeredi * 15423be5a52bSMiklos Szeredi * Remove the bias from the writecounter and send any queued 15433be5a52bSMiklos Szeredi * writepages. 15443be5a52bSMiklos Szeredi */ 15453be5a52bSMiklos Szeredi static void __fuse_release_nowrite(struct inode *inode) 15463be5a52bSMiklos Szeredi { 15473be5a52bSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 15483be5a52bSMiklos Szeredi 15493be5a52bSMiklos Szeredi BUG_ON(fi->writectr != FUSE_NOWRITE); 15503be5a52bSMiklos Szeredi fi->writectr = 0; 15513be5a52bSMiklos Szeredi fuse_flush_writepages(inode); 15523be5a52bSMiklos Szeredi } 15533be5a52bSMiklos Szeredi 15543be5a52bSMiklos Szeredi void fuse_release_nowrite(struct inode *inode) 15553be5a52bSMiklos Szeredi { 15563be5a52bSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 15573be5a52bSMiklos Szeredi 15583be5a52bSMiklos Szeredi spin_lock(&fc->lock); 15593be5a52bSMiklos Szeredi __fuse_release_nowrite(inode); 15603be5a52bSMiklos Szeredi spin_unlock(&fc->lock); 15613be5a52bSMiklos Szeredi } 15623be5a52bSMiklos Szeredi 15633be5a52bSMiklos Szeredi /* 15646f9f1180SMiklos Szeredi * Set attributes, and at the same time refresh them. 15656f9f1180SMiklos Szeredi * 15666f9f1180SMiklos Szeredi * Truncation is slightly complicated, because the 'truncate' request 15676f9f1180SMiklos Szeredi * may fail, in which case we don't want to touch the mapping. 15689ffbb916SMiklos Szeredi * vmtruncate() doesn't allow for this case, so do the rlimit checking 15699ffbb916SMiklos Szeredi * and the actual truncation by hand. 15706f9f1180SMiklos Szeredi */ 1571efb9fa9eSMaxim Patlasov int fuse_do_setattr(struct inode *inode, struct iattr *attr, 157249d4914fSMiklos Szeredi struct file *file) 15739e6268dbSMiklos Szeredi { 15749e6268dbSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 15759e6268dbSMiklos Szeredi struct fuse_req *req; 15769e6268dbSMiklos Szeredi struct fuse_setattr_in inarg; 15779e6268dbSMiklos Szeredi struct fuse_attr_out outarg; 15783be5a52bSMiklos Szeredi bool is_truncate = false; 15793be5a52bSMiklos Szeredi loff_t oldsize; 15809e6268dbSMiklos Szeredi int err; 15819e6268dbSMiklos Szeredi 1582db78b877SChristoph Hellwig if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) 1583db78b877SChristoph Hellwig attr->ia_valid |= ATTR_FORCE; 1584db78b877SChristoph Hellwig 15851e9a4ed9SMiklos Szeredi err = inode_change_ok(inode, attr); 15861e9a4ed9SMiklos Szeredi if (err) 15871e9a4ed9SMiklos Szeredi return err; 15881e9a4ed9SMiklos Szeredi 15898d56adddSMiklos Szeredi if (attr->ia_valid & ATTR_OPEN) { 15908d56adddSMiklos Szeredi if (fc->atomic_o_trunc) 15916ff958edSMiklos Szeredi return 0; 15928d56adddSMiklos Szeredi file = NULL; 15938d56adddSMiklos Szeredi } 15946ff958edSMiklos Szeredi 15952c27c65eSChristoph Hellwig if (attr->ia_valid & ATTR_SIZE) 15963be5a52bSMiklos Szeredi is_truncate = true; 15979e6268dbSMiklos Szeredi 1598b111c8c0SMaxim Patlasov req = fuse_get_req_nopages(fc); 1599ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1600ce1d5a49SMiklos Szeredi return PTR_ERR(req); 16019e6268dbSMiklos Szeredi 16023be5a52bSMiklos Szeredi if (is_truncate) 16033be5a52bSMiklos Szeredi fuse_set_nowrite(inode); 16043be5a52bSMiklos Szeredi 16059e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 16060e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg)); 1607befc649cSMiklos Szeredi iattr_to_fattr(attr, &inarg); 160849d4914fSMiklos Szeredi if (file) { 160949d4914fSMiklos Szeredi struct fuse_file *ff = file->private_data; 161049d4914fSMiklos Szeredi inarg.valid |= FATTR_FH; 161149d4914fSMiklos Szeredi inarg.fh = ff->fh; 161249d4914fSMiklos Szeredi } 1613f3332114SMiklos Szeredi if (attr->ia_valid & ATTR_SIZE) { 1614f3332114SMiklos Szeredi /* For mandatory locking in truncate */ 1615f3332114SMiklos Szeredi inarg.valid |= FATTR_LOCKOWNER; 1616f3332114SMiklos Szeredi inarg.lock_owner = fuse_lock_owner_id(fc, current->files); 1617f3332114SMiklos Szeredi } 16189e6268dbSMiklos Szeredi req->in.h.opcode = FUSE_SETATTR; 16199e6268dbSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 16209e6268dbSMiklos Szeredi req->in.numargs = 1; 16219e6268dbSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 16229e6268dbSMiklos Szeredi req->in.args[0].value = &inarg; 16239e6268dbSMiklos Szeredi req->out.numargs = 1; 16240e9663eeSMiklos Szeredi if (fc->minor < 9) 16250e9663eeSMiklos Szeredi req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; 16260e9663eeSMiklos Szeredi else 16279e6268dbSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 16289e6268dbSMiklos Szeredi req->out.args[0].value = &outarg; 1629b93f858aSTejun Heo fuse_request_send(fc, req); 16309e6268dbSMiklos Szeredi err = req->out.h.error; 16319e6268dbSMiklos Szeredi fuse_put_request(fc, req); 1632e00d2c2dSMiklos Szeredi if (err) { 1633e00d2c2dSMiklos Szeredi if (err == -EINTR) 1634e00d2c2dSMiklos Szeredi fuse_invalidate_attr(inode); 16353be5a52bSMiklos Szeredi goto error; 1636e00d2c2dSMiklos Szeredi } 1637e00d2c2dSMiklos Szeredi 16389e6268dbSMiklos Szeredi if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { 16399e6268dbSMiklos Szeredi make_bad_inode(inode); 16403be5a52bSMiklos Szeredi err = -EIO; 16413be5a52bSMiklos Szeredi goto error; 16429e6268dbSMiklos Szeredi } 16439e6268dbSMiklos Szeredi 16443be5a52bSMiklos Szeredi spin_lock(&fc->lock); 16453be5a52bSMiklos Szeredi fuse_change_attributes_common(inode, &outarg.attr, 16463be5a52bSMiklos Szeredi attr_timeout(&outarg)); 16473be5a52bSMiklos Szeredi oldsize = inode->i_size; 16483be5a52bSMiklos Szeredi i_size_write(inode, outarg.attr.size); 16493be5a52bSMiklos Szeredi 16503be5a52bSMiklos Szeredi if (is_truncate) { 16513be5a52bSMiklos Szeredi /* NOTE: this may release/reacquire fc->lock */ 16523be5a52bSMiklos Szeredi __fuse_release_nowrite(inode); 16533be5a52bSMiklos Szeredi } 16543be5a52bSMiklos Szeredi spin_unlock(&fc->lock); 16553be5a52bSMiklos Szeredi 16563be5a52bSMiklos Szeredi /* 16573be5a52bSMiklos Szeredi * Only call invalidate_inode_pages2() after removing 16583be5a52bSMiklos Szeredi * FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock. 16593be5a52bSMiklos Szeredi */ 16603be5a52bSMiklos Szeredi if (S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) { 1661c08d3b0eSnpiggin@suse.de truncate_pagecache(inode, oldsize, outarg.attr.size); 16623be5a52bSMiklos Szeredi invalidate_inode_pages2(inode->i_mapping); 16633be5a52bSMiklos Szeredi } 16643be5a52bSMiklos Szeredi 1665e00d2c2dSMiklos Szeredi return 0; 16663be5a52bSMiklos Szeredi 16673be5a52bSMiklos Szeredi error: 16683be5a52bSMiklos Szeredi if (is_truncate) 16693be5a52bSMiklos Szeredi fuse_release_nowrite(inode); 16703be5a52bSMiklos Szeredi 16713be5a52bSMiklos Szeredi return err; 16729e6268dbSMiklos Szeredi } 16739e6268dbSMiklos Szeredi 167449d4914fSMiklos Szeredi static int fuse_setattr(struct dentry *entry, struct iattr *attr) 167549d4914fSMiklos Szeredi { 1676efb9fa9eSMaxim Patlasov struct inode *inode = entry->d_inode; 1677efb9fa9eSMaxim Patlasov 1678efb9fa9eSMaxim Patlasov if (!fuse_allow_current_process(get_fuse_conn(inode))) 1679efb9fa9eSMaxim Patlasov return -EACCES; 1680efb9fa9eSMaxim Patlasov 168149d4914fSMiklos Szeredi if (attr->ia_valid & ATTR_FILE) 1682efb9fa9eSMaxim Patlasov return fuse_do_setattr(inode, attr, attr->ia_file); 168349d4914fSMiklos Szeredi else 1684efb9fa9eSMaxim Patlasov return fuse_do_setattr(inode, attr, NULL); 168549d4914fSMiklos Szeredi } 168649d4914fSMiklos Szeredi 1687e5e5558eSMiklos Szeredi static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, 1688e5e5558eSMiklos Szeredi struct kstat *stat) 1689e5e5558eSMiklos Szeredi { 1690e5e5558eSMiklos Szeredi struct inode *inode = entry->d_inode; 1691244f6385SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 1692244f6385SMiklos Szeredi 1693c2132c1bSAnatol Pomozov if (!fuse_allow_current_process(fc)) 1694244f6385SMiklos Szeredi return -EACCES; 1695244f6385SMiklos Szeredi 1696bcb4be80SMiklos Szeredi return fuse_update_attributes(inode, stat, NULL, NULL); 1697e5e5558eSMiklos Szeredi } 1698e5e5558eSMiklos Szeredi 169992a8780eSMiklos Szeredi static int fuse_setxattr(struct dentry *entry, const char *name, 170092a8780eSMiklos Szeredi const void *value, size_t size, int flags) 170192a8780eSMiklos Szeredi { 170292a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 170392a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 170492a8780eSMiklos Szeredi struct fuse_req *req; 170592a8780eSMiklos Szeredi struct fuse_setxattr_in inarg; 170692a8780eSMiklos Szeredi int err; 170792a8780eSMiklos Szeredi 170892a8780eSMiklos Szeredi if (fc->no_setxattr) 170992a8780eSMiklos Szeredi return -EOPNOTSUPP; 171092a8780eSMiklos Szeredi 1711b111c8c0SMaxim Patlasov req = fuse_get_req_nopages(fc); 1712ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1713ce1d5a49SMiklos Szeredi return PTR_ERR(req); 171492a8780eSMiklos Szeredi 171592a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 171692a8780eSMiklos Szeredi inarg.size = size; 171792a8780eSMiklos Szeredi inarg.flags = flags; 171892a8780eSMiklos Szeredi req->in.h.opcode = FUSE_SETXATTR; 171992a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 172092a8780eSMiklos Szeredi req->in.numargs = 3; 172192a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 172292a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 172392a8780eSMiklos Szeredi req->in.args[1].size = strlen(name) + 1; 172492a8780eSMiklos Szeredi req->in.args[1].value = name; 172592a8780eSMiklos Szeredi req->in.args[2].size = size; 172692a8780eSMiklos Szeredi req->in.args[2].value = value; 1727b93f858aSTejun Heo fuse_request_send(fc, req); 172892a8780eSMiklos Szeredi err = req->out.h.error; 172992a8780eSMiklos Szeredi fuse_put_request(fc, req); 173092a8780eSMiklos Szeredi if (err == -ENOSYS) { 173192a8780eSMiklos Szeredi fc->no_setxattr = 1; 173292a8780eSMiklos Szeredi err = -EOPNOTSUPP; 173392a8780eSMiklos Szeredi } 173492a8780eSMiklos Szeredi return err; 173592a8780eSMiklos Szeredi } 173692a8780eSMiklos Szeredi 173792a8780eSMiklos Szeredi static ssize_t fuse_getxattr(struct dentry *entry, const char *name, 173892a8780eSMiklos Szeredi void *value, size_t size) 173992a8780eSMiklos Szeredi { 174092a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 174192a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 174292a8780eSMiklos Szeredi struct fuse_req *req; 174392a8780eSMiklos Szeredi struct fuse_getxattr_in inarg; 174492a8780eSMiklos Szeredi struct fuse_getxattr_out outarg; 174592a8780eSMiklos Szeredi ssize_t ret; 174692a8780eSMiklos Szeredi 174792a8780eSMiklos Szeredi if (fc->no_getxattr) 174892a8780eSMiklos Szeredi return -EOPNOTSUPP; 174992a8780eSMiklos Szeredi 1750b111c8c0SMaxim Patlasov req = fuse_get_req_nopages(fc); 1751ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1752ce1d5a49SMiklos Szeredi return PTR_ERR(req); 175392a8780eSMiklos Szeredi 175492a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 175592a8780eSMiklos Szeredi inarg.size = size; 175692a8780eSMiklos Szeredi req->in.h.opcode = FUSE_GETXATTR; 175792a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 175892a8780eSMiklos Szeredi req->in.numargs = 2; 175992a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 176092a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 176192a8780eSMiklos Szeredi req->in.args[1].size = strlen(name) + 1; 176292a8780eSMiklos Szeredi req->in.args[1].value = name; 176392a8780eSMiklos Szeredi /* This is really two different operations rolled into one */ 176492a8780eSMiklos Szeredi req->out.numargs = 1; 176592a8780eSMiklos Szeredi if (size) { 176692a8780eSMiklos Szeredi req->out.argvar = 1; 176792a8780eSMiklos Szeredi req->out.args[0].size = size; 176892a8780eSMiklos Szeredi req->out.args[0].value = value; 176992a8780eSMiklos Szeredi } else { 177092a8780eSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 177192a8780eSMiklos Szeredi req->out.args[0].value = &outarg; 177292a8780eSMiklos Szeredi } 1773b93f858aSTejun Heo fuse_request_send(fc, req); 177492a8780eSMiklos Szeredi ret = req->out.h.error; 177592a8780eSMiklos Szeredi if (!ret) 177692a8780eSMiklos Szeredi ret = size ? req->out.args[0].size : outarg.size; 177792a8780eSMiklos Szeredi else { 177892a8780eSMiklos Szeredi if (ret == -ENOSYS) { 177992a8780eSMiklos Szeredi fc->no_getxattr = 1; 178092a8780eSMiklos Szeredi ret = -EOPNOTSUPP; 178192a8780eSMiklos Szeredi } 178292a8780eSMiklos Szeredi } 178392a8780eSMiklos Szeredi fuse_put_request(fc, req); 178492a8780eSMiklos Szeredi return ret; 178592a8780eSMiklos Szeredi } 178692a8780eSMiklos Szeredi 178792a8780eSMiklos Szeredi static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) 178892a8780eSMiklos Szeredi { 178992a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 179092a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 179192a8780eSMiklos Szeredi struct fuse_req *req; 179292a8780eSMiklos Szeredi struct fuse_getxattr_in inarg; 179392a8780eSMiklos Szeredi struct fuse_getxattr_out outarg; 179492a8780eSMiklos Szeredi ssize_t ret; 179592a8780eSMiklos Szeredi 1796c2132c1bSAnatol Pomozov if (!fuse_allow_current_process(fc)) 1797e57ac683SMiklos Szeredi return -EACCES; 1798e57ac683SMiklos Szeredi 179992a8780eSMiklos Szeredi if (fc->no_listxattr) 180092a8780eSMiklos Szeredi return -EOPNOTSUPP; 180192a8780eSMiklos Szeredi 1802b111c8c0SMaxim Patlasov req = fuse_get_req_nopages(fc); 1803ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1804ce1d5a49SMiklos Szeredi return PTR_ERR(req); 180592a8780eSMiklos Szeredi 180692a8780eSMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 180792a8780eSMiklos Szeredi inarg.size = size; 180892a8780eSMiklos Szeredi req->in.h.opcode = FUSE_LISTXATTR; 180992a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 181092a8780eSMiklos Szeredi req->in.numargs = 1; 181192a8780eSMiklos Szeredi req->in.args[0].size = sizeof(inarg); 181292a8780eSMiklos Szeredi req->in.args[0].value = &inarg; 181392a8780eSMiklos Szeredi /* This is really two different operations rolled into one */ 181492a8780eSMiklos Szeredi req->out.numargs = 1; 181592a8780eSMiklos Szeredi if (size) { 181692a8780eSMiklos Szeredi req->out.argvar = 1; 181792a8780eSMiklos Szeredi req->out.args[0].size = size; 181892a8780eSMiklos Szeredi req->out.args[0].value = list; 181992a8780eSMiklos Szeredi } else { 182092a8780eSMiklos Szeredi req->out.args[0].size = sizeof(outarg); 182192a8780eSMiklos Szeredi req->out.args[0].value = &outarg; 182292a8780eSMiklos Szeredi } 1823b93f858aSTejun Heo fuse_request_send(fc, req); 182492a8780eSMiklos Szeredi ret = req->out.h.error; 182592a8780eSMiklos Szeredi if (!ret) 182692a8780eSMiklos Szeredi ret = size ? req->out.args[0].size : outarg.size; 182792a8780eSMiklos Szeredi else { 182892a8780eSMiklos Szeredi if (ret == -ENOSYS) { 182992a8780eSMiklos Szeredi fc->no_listxattr = 1; 183092a8780eSMiklos Szeredi ret = -EOPNOTSUPP; 183192a8780eSMiklos Szeredi } 183292a8780eSMiklos Szeredi } 183392a8780eSMiklos Szeredi fuse_put_request(fc, req); 183492a8780eSMiklos Szeredi return ret; 183592a8780eSMiklos Szeredi } 183692a8780eSMiklos Szeredi 183792a8780eSMiklos Szeredi static int fuse_removexattr(struct dentry *entry, const char *name) 183892a8780eSMiklos Szeredi { 183992a8780eSMiklos Szeredi struct inode *inode = entry->d_inode; 184092a8780eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 184192a8780eSMiklos Szeredi struct fuse_req *req; 184292a8780eSMiklos Szeredi int err; 184392a8780eSMiklos Szeredi 184492a8780eSMiklos Szeredi if (fc->no_removexattr) 184592a8780eSMiklos Szeredi return -EOPNOTSUPP; 184692a8780eSMiklos Szeredi 1847b111c8c0SMaxim Patlasov req = fuse_get_req_nopages(fc); 1848ce1d5a49SMiklos Szeredi if (IS_ERR(req)) 1849ce1d5a49SMiklos Szeredi return PTR_ERR(req); 185092a8780eSMiklos Szeredi 185192a8780eSMiklos Szeredi req->in.h.opcode = FUSE_REMOVEXATTR; 185292a8780eSMiklos Szeredi req->in.h.nodeid = get_node_id(inode); 185392a8780eSMiklos Szeredi req->in.numargs = 1; 185492a8780eSMiklos Szeredi req->in.args[0].size = strlen(name) + 1; 185592a8780eSMiklos Szeredi req->in.args[0].value = name; 1856b93f858aSTejun Heo fuse_request_send(fc, req); 185792a8780eSMiklos Szeredi err = req->out.h.error; 185892a8780eSMiklos Szeredi fuse_put_request(fc, req); 185992a8780eSMiklos Szeredi if (err == -ENOSYS) { 186092a8780eSMiklos Szeredi fc->no_removexattr = 1; 186192a8780eSMiklos Szeredi err = -EOPNOTSUPP; 186292a8780eSMiklos Szeredi } 186392a8780eSMiklos Szeredi return err; 186492a8780eSMiklos Szeredi } 186592a8780eSMiklos Szeredi 1866754661f1SArjan van de Ven static const struct inode_operations fuse_dir_inode_operations = { 1867e5e5558eSMiklos Szeredi .lookup = fuse_lookup, 18689e6268dbSMiklos Szeredi .mkdir = fuse_mkdir, 18699e6268dbSMiklos Szeredi .symlink = fuse_symlink, 18709e6268dbSMiklos Szeredi .unlink = fuse_unlink, 18719e6268dbSMiklos Szeredi .rmdir = fuse_rmdir, 18729e6268dbSMiklos Szeredi .rename = fuse_rename, 18739e6268dbSMiklos Szeredi .link = fuse_link, 18749e6268dbSMiklos Szeredi .setattr = fuse_setattr, 18759e6268dbSMiklos Szeredi .create = fuse_create, 1876c8ccbe03SMiklos Szeredi .atomic_open = fuse_atomic_open, 18779e6268dbSMiklos Szeredi .mknod = fuse_mknod, 1878e5e5558eSMiklos Szeredi .permission = fuse_permission, 1879e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 188092a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 188192a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 188292a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 188392a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 1884e5e5558eSMiklos Szeredi }; 1885e5e5558eSMiklos Szeredi 18864b6f5d20SArjan van de Ven static const struct file_operations fuse_dir_operations = { 1887b6aeadedSMiklos Szeredi .llseek = generic_file_llseek, 1888e5e5558eSMiklos Szeredi .read = generic_read_dir, 1889e5e5558eSMiklos Szeredi .readdir = fuse_readdir, 1890e5e5558eSMiklos Szeredi .open = fuse_dir_open, 1891e5e5558eSMiklos Szeredi .release = fuse_dir_release, 189282547981SMiklos Szeredi .fsync = fuse_dir_fsync, 1893b18da0c5SMiklos Szeredi .unlocked_ioctl = fuse_dir_ioctl, 1894b18da0c5SMiklos Szeredi .compat_ioctl = fuse_dir_compat_ioctl, 1895e5e5558eSMiklos Szeredi }; 1896e5e5558eSMiklos Szeredi 1897754661f1SArjan van de Ven static const struct inode_operations fuse_common_inode_operations = { 18989e6268dbSMiklos Szeredi .setattr = fuse_setattr, 1899e5e5558eSMiklos Szeredi .permission = fuse_permission, 1900e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 190192a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 190292a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 190392a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 190492a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 1905e5e5558eSMiklos Szeredi }; 1906e5e5558eSMiklos Szeredi 1907754661f1SArjan van de Ven static const struct inode_operations fuse_symlink_inode_operations = { 19089e6268dbSMiklos Szeredi .setattr = fuse_setattr, 1909e5e5558eSMiklos Szeredi .follow_link = fuse_follow_link, 1910e5e5558eSMiklos Szeredi .put_link = fuse_put_link, 1911e5e5558eSMiklos Szeredi .readlink = generic_readlink, 1912e5e5558eSMiklos Szeredi .getattr = fuse_getattr, 191392a8780eSMiklos Szeredi .setxattr = fuse_setxattr, 191492a8780eSMiklos Szeredi .getxattr = fuse_getxattr, 191592a8780eSMiklos Szeredi .listxattr = fuse_listxattr, 191692a8780eSMiklos Szeredi .removexattr = fuse_removexattr, 1917e5e5558eSMiklos Szeredi }; 1918e5e5558eSMiklos Szeredi 1919e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode) 1920e5e5558eSMiklos Szeredi { 1921e5e5558eSMiklos Szeredi inode->i_op = &fuse_common_inode_operations; 1922e5e5558eSMiklos Szeredi } 1923e5e5558eSMiklos Szeredi 1924e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode) 1925e5e5558eSMiklos Szeredi { 1926e5e5558eSMiklos Szeredi inode->i_op = &fuse_dir_inode_operations; 1927e5e5558eSMiklos Szeredi inode->i_fop = &fuse_dir_operations; 1928e5e5558eSMiklos Szeredi } 1929e5e5558eSMiklos Szeredi 1930e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode) 1931e5e5558eSMiklos Szeredi { 1932e5e5558eSMiklos Szeredi inode->i_op = &fuse_symlink_inode_operations; 1933e5e5558eSMiklos Szeredi } 1934