1d123d8e1SMiklos Szeredi /* 2d123d8e1SMiklos Szeredi FUSE: Filesystem in Userspace 3d123d8e1SMiklos Szeredi Copyright (C) 2001-2018 Miklos Szeredi <miklos@szeredi.hu> 4d123d8e1SMiklos Szeredi 5d123d8e1SMiklos Szeredi This program can be distributed under the terms of the GNU GPL. 6d123d8e1SMiklos Szeredi See the file COPYING. 7d123d8e1SMiklos Szeredi */ 8d123d8e1SMiklos Szeredi 9d123d8e1SMiklos Szeredi 10d123d8e1SMiklos Szeredi #include "fuse_i.h" 11261aaba7SMiklos Szeredi #include <linux/iversion.h> 12d123d8e1SMiklos Szeredi #include <linux/posix_acl.h> 1369e34551SMiklos Szeredi #include <linux/pagemap.h> 1469e34551SMiklos Szeredi #include <linux/highmem.h> 15d123d8e1SMiklos Szeredi 16d123d8e1SMiklos Szeredi static bool fuse_use_readdirplus(struct inode *dir, struct dir_context *ctx) 17d123d8e1SMiklos Szeredi { 18d123d8e1SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir); 19d123d8e1SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(dir); 20d123d8e1SMiklos Szeredi 21d123d8e1SMiklos Szeredi if (!fc->do_readdirplus) 22d123d8e1SMiklos Szeredi return false; 23d123d8e1SMiklos Szeredi if (!fc->readdirplus_auto) 24d123d8e1SMiklos Szeredi return true; 25d123d8e1SMiklos Szeredi if (test_and_clear_bit(FUSE_I_ADVISE_RDPLUS, &fi->state)) 26d123d8e1SMiklos Szeredi return true; 27d123d8e1SMiklos Szeredi if (ctx->pos == 0) 28d123d8e1SMiklos Szeredi return true; 29d123d8e1SMiklos Szeredi return false; 30d123d8e1SMiklos Szeredi } 31d123d8e1SMiklos Szeredi 3269e34551SMiklos Szeredi static void fuse_add_dirent_to_cache(struct file *file, 3369e34551SMiklos Szeredi struct fuse_dirent *dirent, loff_t pos) 3469e34551SMiklos Szeredi { 3569e34551SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(file_inode(file)); 3669e34551SMiklos Szeredi size_t reclen = FUSE_DIRENT_SIZE(dirent); 3769e34551SMiklos Szeredi pgoff_t index; 3869e34551SMiklos Szeredi struct page *page; 3969e34551SMiklos Szeredi loff_t size; 403494927eSMiklos Szeredi u64 version; 4169e34551SMiklos Szeredi unsigned int offset; 4269e34551SMiklos Szeredi void *addr; 4369e34551SMiklos Szeredi 4469e34551SMiklos Szeredi spin_lock(&fi->rdc.lock); 4569e34551SMiklos Szeredi /* 4669e34551SMiklos Szeredi * Is cache already completed? Or this entry does not go at the end of 4769e34551SMiklos Szeredi * cache? 4869e34551SMiklos Szeredi */ 4969e34551SMiklos Szeredi if (fi->rdc.cached || pos != fi->rdc.pos) { 5069e34551SMiklos Szeredi spin_unlock(&fi->rdc.lock); 5169e34551SMiklos Szeredi return; 5269e34551SMiklos Szeredi } 533494927eSMiklos Szeredi version = fi->rdc.version; 5469e34551SMiklos Szeredi size = fi->rdc.size; 5569e34551SMiklos Szeredi offset = size & ~PAGE_MASK; 5669e34551SMiklos Szeredi index = size >> PAGE_SHIFT; 5769e34551SMiklos Szeredi /* Dirent doesn't fit in current page? Jump to next page. */ 5869e34551SMiklos Szeredi if (offset + reclen > PAGE_SIZE) { 5969e34551SMiklos Szeredi index++; 6069e34551SMiklos Szeredi offset = 0; 6169e34551SMiklos Szeredi } 6269e34551SMiklos Szeredi spin_unlock(&fi->rdc.lock); 6369e34551SMiklos Szeredi 6469e34551SMiklos Szeredi if (offset) { 6569e34551SMiklos Szeredi page = find_lock_page(file->f_mapping, index); 6669e34551SMiklos Szeredi } else { 6769e34551SMiklos Szeredi page = find_or_create_page(file->f_mapping, index, 6869e34551SMiklos Szeredi mapping_gfp_mask(file->f_mapping)); 6969e34551SMiklos Szeredi } 7069e34551SMiklos Szeredi if (!page) 7169e34551SMiklos Szeredi return; 7269e34551SMiklos Szeredi 7369e34551SMiklos Szeredi spin_lock(&fi->rdc.lock); 7469e34551SMiklos Szeredi /* Raced with another readdir */ 753494927eSMiklos Szeredi if (fi->rdc.version != version || fi->rdc.size != size || 763494927eSMiklos Szeredi WARN_ON(fi->rdc.pos != pos)) 7769e34551SMiklos Szeredi goto unlock; 7869e34551SMiklos Szeredi 7969e34551SMiklos Szeredi addr = kmap_atomic(page); 8069e34551SMiklos Szeredi if (!offset) 8169e34551SMiklos Szeredi clear_page(addr); 8269e34551SMiklos Szeredi memcpy(addr + offset, dirent, reclen); 8369e34551SMiklos Szeredi kunmap_atomic(addr); 8469e34551SMiklos Szeredi fi->rdc.size = (index << PAGE_SHIFT) + offset + reclen; 8569e34551SMiklos Szeredi fi->rdc.pos = dirent->off; 8669e34551SMiklos Szeredi unlock: 8769e34551SMiklos Szeredi spin_unlock(&fi->rdc.lock); 8869e34551SMiklos Szeredi unlock_page(page); 8969e34551SMiklos Szeredi put_page(page); 9069e34551SMiklos Szeredi } 9169e34551SMiklos Szeredi 9269e34551SMiklos Szeredi static void fuse_readdir_cache_end(struct file *file, loff_t pos) 9369e34551SMiklos Szeredi { 9469e34551SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(file_inode(file)); 9569e34551SMiklos Szeredi loff_t end; 9669e34551SMiklos Szeredi 9769e34551SMiklos Szeredi spin_lock(&fi->rdc.lock); 9869e34551SMiklos Szeredi /* does cache end position match current position? */ 9969e34551SMiklos Szeredi if (fi->rdc.pos != pos) { 10069e34551SMiklos Szeredi spin_unlock(&fi->rdc.lock); 10169e34551SMiklos Szeredi return; 10269e34551SMiklos Szeredi } 10369e34551SMiklos Szeredi 10469e34551SMiklos Szeredi fi->rdc.cached = true; 10569e34551SMiklos Szeredi end = ALIGN(fi->rdc.size, PAGE_SIZE); 10669e34551SMiklos Szeredi spin_unlock(&fi->rdc.lock); 10769e34551SMiklos Szeredi 10869e34551SMiklos Szeredi /* truncate unused tail of cache */ 10969e34551SMiklos Szeredi truncate_inode_pages(file->f_mapping, end); 11069e34551SMiklos Szeredi } 11169e34551SMiklos Szeredi 11218172b10SMiklos Szeredi static bool fuse_emit(struct file *file, struct dir_context *ctx, 11318172b10SMiklos Szeredi struct fuse_dirent *dirent) 11418172b10SMiklos Szeredi { 11569e34551SMiklos Szeredi struct fuse_file *ff = file->private_data; 11669e34551SMiklos Szeredi 11769e34551SMiklos Szeredi if (ff->open_flags & FOPEN_CACHE_DIR) 11869e34551SMiklos Szeredi fuse_add_dirent_to_cache(file, dirent, ctx->pos); 11969e34551SMiklos Szeredi 12018172b10SMiklos Szeredi return dir_emit(ctx, dirent->name, dirent->namelen, dirent->ino, 12118172b10SMiklos Szeredi dirent->type); 12218172b10SMiklos Szeredi } 12318172b10SMiklos Szeredi 124d123d8e1SMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file, 125d123d8e1SMiklos Szeredi struct dir_context *ctx) 126d123d8e1SMiklos Szeredi { 127d123d8e1SMiklos Szeredi while (nbytes >= FUSE_NAME_OFFSET) { 128d123d8e1SMiklos Szeredi struct fuse_dirent *dirent = (struct fuse_dirent *) buf; 129d123d8e1SMiklos Szeredi size_t reclen = FUSE_DIRENT_SIZE(dirent); 130d123d8e1SMiklos Szeredi if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) 131d123d8e1SMiklos Szeredi return -EIO; 132d123d8e1SMiklos Szeredi if (reclen > nbytes) 133d123d8e1SMiklos Szeredi break; 134d123d8e1SMiklos Szeredi if (memchr(dirent->name, '/', dirent->namelen) != NULL) 135d123d8e1SMiklos Szeredi return -EIO; 136d123d8e1SMiklos Szeredi 13718172b10SMiklos Szeredi if (!fuse_emit(file, ctx, dirent)) 138d123d8e1SMiklos Szeredi break; 139d123d8e1SMiklos Szeredi 140d123d8e1SMiklos Szeredi buf += reclen; 141d123d8e1SMiklos Szeredi nbytes -= reclen; 142d123d8e1SMiklos Szeredi ctx->pos = dirent->off; 143d123d8e1SMiklos Szeredi } 144d123d8e1SMiklos Szeredi 145d123d8e1SMiklos Szeredi return 0; 146d123d8e1SMiklos Szeredi } 147d123d8e1SMiklos Szeredi 148d123d8e1SMiklos Szeredi static int fuse_direntplus_link(struct file *file, 149d123d8e1SMiklos Szeredi struct fuse_direntplus *direntplus, 150d123d8e1SMiklos Szeredi u64 attr_version) 151d123d8e1SMiklos Szeredi { 152d123d8e1SMiklos Szeredi struct fuse_entry_out *o = &direntplus->entry_out; 153d123d8e1SMiklos Szeredi struct fuse_dirent *dirent = &direntplus->dirent; 154d123d8e1SMiklos Szeredi struct dentry *parent = file->f_path.dentry; 155d123d8e1SMiklos Szeredi struct qstr name = QSTR_INIT(dirent->name, dirent->namelen); 156d123d8e1SMiklos Szeredi struct dentry *dentry; 157d123d8e1SMiklos Szeredi struct dentry *alias; 158d123d8e1SMiklos Szeredi struct inode *dir = d_inode(parent); 159d123d8e1SMiklos Szeredi struct fuse_conn *fc; 160d123d8e1SMiklos Szeredi struct inode *inode; 161d123d8e1SMiklos Szeredi DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); 162d123d8e1SMiklos Szeredi 163d123d8e1SMiklos Szeredi if (!o->nodeid) { 164d123d8e1SMiklos Szeredi /* 165d123d8e1SMiklos Szeredi * Unlike in the case of fuse_lookup, zero nodeid does not mean 166d123d8e1SMiklos Szeredi * ENOENT. Instead, it only means the userspace filesystem did 167d123d8e1SMiklos Szeredi * not want to return attributes/handle for this entry. 168d123d8e1SMiklos Szeredi * 169d123d8e1SMiklos Szeredi * So do nothing. 170d123d8e1SMiklos Szeredi */ 171d123d8e1SMiklos Szeredi return 0; 172d123d8e1SMiklos Szeredi } 173d123d8e1SMiklos Szeredi 174d123d8e1SMiklos Szeredi if (name.name[0] == '.') { 175d123d8e1SMiklos Szeredi /* 176d123d8e1SMiklos Szeredi * We could potentially refresh the attributes of the directory 177d123d8e1SMiklos Szeredi * and its parent? 178d123d8e1SMiklos Szeredi */ 179d123d8e1SMiklos Szeredi if (name.len == 1) 180d123d8e1SMiklos Szeredi return 0; 181d123d8e1SMiklos Szeredi if (name.name[1] == '.' && name.len == 2) 182d123d8e1SMiklos Szeredi return 0; 183d123d8e1SMiklos Szeredi } 184d123d8e1SMiklos Szeredi 185d123d8e1SMiklos Szeredi if (invalid_nodeid(o->nodeid)) 186d123d8e1SMiklos Szeredi return -EIO; 187eb59bd17SMiklos Szeredi if (fuse_invalid_attr(&o->attr)) 188d123d8e1SMiklos Szeredi return -EIO; 189d123d8e1SMiklos Szeredi 190d123d8e1SMiklos Szeredi fc = get_fuse_conn(dir); 191d123d8e1SMiklos Szeredi 192d123d8e1SMiklos Szeredi name.hash = full_name_hash(parent, name.name, name.len); 193d123d8e1SMiklos Szeredi dentry = d_lookup(parent, &name); 194d123d8e1SMiklos Szeredi if (!dentry) { 195d123d8e1SMiklos Szeredi retry: 196d123d8e1SMiklos Szeredi dentry = d_alloc_parallel(parent, &name, &wq); 197d123d8e1SMiklos Szeredi if (IS_ERR(dentry)) 198d123d8e1SMiklos Szeredi return PTR_ERR(dentry); 199d123d8e1SMiklos Szeredi } 200d123d8e1SMiklos Szeredi if (!d_in_lookup(dentry)) { 201d123d8e1SMiklos Szeredi struct fuse_inode *fi; 202d123d8e1SMiklos Szeredi inode = d_inode(dentry); 203d123d8e1SMiklos Szeredi if (!inode || 204d123d8e1SMiklos Szeredi get_node_id(inode) != o->nodeid || 205d123d8e1SMiklos Szeredi ((o->attr.mode ^ inode->i_mode) & S_IFMT)) { 206d123d8e1SMiklos Szeredi d_invalidate(dentry); 207d123d8e1SMiklos Szeredi dput(dentry); 208d123d8e1SMiklos Szeredi goto retry; 209d123d8e1SMiklos Szeredi } 210d123d8e1SMiklos Szeredi if (is_bad_inode(inode)) { 211d123d8e1SMiklos Szeredi dput(dentry); 212d123d8e1SMiklos Szeredi return -EIO; 213d123d8e1SMiklos Szeredi } 214d123d8e1SMiklos Szeredi 215d123d8e1SMiklos Szeredi fi = get_fuse_inode(inode); 216c9d8f5f0SKirill Tkhai spin_lock(&fi->lock); 217d123d8e1SMiklos Szeredi fi->nlookup++; 218c9d8f5f0SKirill Tkhai spin_unlock(&fi->lock); 219d123d8e1SMiklos Szeredi 220d123d8e1SMiklos Szeredi forget_all_cached_acls(inode); 221d123d8e1SMiklos Szeredi fuse_change_attributes(inode, &o->attr, 222d123d8e1SMiklos Szeredi entry_attr_timeout(o), 223d123d8e1SMiklos Szeredi attr_version); 224d123d8e1SMiklos Szeredi /* 225d123d8e1SMiklos Szeredi * The other branch comes via fuse_iget() 226d123d8e1SMiklos Szeredi * which bumps nlookup inside 227d123d8e1SMiklos Szeredi */ 228d123d8e1SMiklos Szeredi } else { 229d123d8e1SMiklos Szeredi inode = fuse_iget(dir->i_sb, o->nodeid, o->generation, 230d123d8e1SMiklos Szeredi &o->attr, entry_attr_timeout(o), 231d123d8e1SMiklos Szeredi attr_version); 232d123d8e1SMiklos Szeredi if (!inode) 233d123d8e1SMiklos Szeredi inode = ERR_PTR(-ENOMEM); 234d123d8e1SMiklos Szeredi 235d123d8e1SMiklos Szeredi alias = d_splice_alias(inode, dentry); 236d123d8e1SMiklos Szeredi d_lookup_done(dentry); 237d123d8e1SMiklos Szeredi if (alias) { 238d123d8e1SMiklos Szeredi dput(dentry); 239d123d8e1SMiklos Szeredi dentry = alias; 240d123d8e1SMiklos Szeredi } 241d123d8e1SMiklos Szeredi if (IS_ERR(dentry)) 242d123d8e1SMiklos Szeredi return PTR_ERR(dentry); 243d123d8e1SMiklos Szeredi } 244d123d8e1SMiklos Szeredi if (fc->readdirplus_auto) 245d123d8e1SMiklos Szeredi set_bit(FUSE_I_INIT_RDPLUS, &get_fuse_inode(inode)->state); 246d123d8e1SMiklos Szeredi fuse_change_entry_timeout(dentry, o); 247d123d8e1SMiklos Szeredi 248d123d8e1SMiklos Szeredi dput(dentry); 249d123d8e1SMiklos Szeredi return 0; 250d123d8e1SMiklos Szeredi } 251d123d8e1SMiklos Szeredi 2523545fe21SMiklos Szeredi static void fuse_force_forget(struct file *file, u64 nodeid) 2533545fe21SMiklos Szeredi { 2543545fe21SMiklos Szeredi struct inode *inode = file_inode(file); 255*fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(inode); 2563545fe21SMiklos Szeredi struct fuse_forget_in inarg; 2573545fe21SMiklos Szeredi FUSE_ARGS(args); 2583545fe21SMiklos Szeredi 2593545fe21SMiklos Szeredi memset(&inarg, 0, sizeof(inarg)); 2603545fe21SMiklos Szeredi inarg.nlookup = 1; 2613545fe21SMiklos Szeredi args.opcode = FUSE_FORGET; 2623545fe21SMiklos Szeredi args.nodeid = nodeid; 2633545fe21SMiklos Szeredi args.in_numargs = 1; 2643545fe21SMiklos Szeredi args.in_args[0].size = sizeof(inarg); 2653545fe21SMiklos Szeredi args.in_args[0].value = &inarg; 2663545fe21SMiklos Szeredi args.force = true; 2673545fe21SMiklos Szeredi args.noreply = true; 2683545fe21SMiklos Szeredi 269*fcee216bSMax Reitz fuse_simple_request(fm, &args); 2703545fe21SMiklos Szeredi /* ignore errors */ 2713545fe21SMiklos Szeredi } 2723545fe21SMiklos Szeredi 273d123d8e1SMiklos Szeredi static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file, 274d123d8e1SMiklos Szeredi struct dir_context *ctx, u64 attr_version) 275d123d8e1SMiklos Szeredi { 276d123d8e1SMiklos Szeredi struct fuse_direntplus *direntplus; 277d123d8e1SMiklos Szeredi struct fuse_dirent *dirent; 278d123d8e1SMiklos Szeredi size_t reclen; 279d123d8e1SMiklos Szeredi int over = 0; 280d123d8e1SMiklos Szeredi int ret; 281d123d8e1SMiklos Szeredi 282d123d8e1SMiklos Szeredi while (nbytes >= FUSE_NAME_OFFSET_DIRENTPLUS) { 283d123d8e1SMiklos Szeredi direntplus = (struct fuse_direntplus *) buf; 284d123d8e1SMiklos Szeredi dirent = &direntplus->dirent; 285d123d8e1SMiklos Szeredi reclen = FUSE_DIRENTPLUS_SIZE(direntplus); 286d123d8e1SMiklos Szeredi 287d123d8e1SMiklos Szeredi if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) 288d123d8e1SMiklos Szeredi return -EIO; 289d123d8e1SMiklos Szeredi if (reclen > nbytes) 290d123d8e1SMiklos Szeredi break; 291d123d8e1SMiklos Szeredi if (memchr(dirent->name, '/', dirent->namelen) != NULL) 292d123d8e1SMiklos Szeredi return -EIO; 293d123d8e1SMiklos Szeredi 294d123d8e1SMiklos Szeredi if (!over) { 295d123d8e1SMiklos Szeredi /* We fill entries into dstbuf only as much as 296d123d8e1SMiklos Szeredi it can hold. But we still continue iterating 297d123d8e1SMiklos Szeredi over remaining entries to link them. If not, 298d123d8e1SMiklos Szeredi we need to send a FORGET for each of those 299d123d8e1SMiklos Szeredi which we did not link. 300d123d8e1SMiklos Szeredi */ 30118172b10SMiklos Szeredi over = !fuse_emit(file, ctx, dirent); 302d123d8e1SMiklos Szeredi if (!over) 303d123d8e1SMiklos Szeredi ctx->pos = dirent->off; 304d123d8e1SMiklos Szeredi } 305d123d8e1SMiklos Szeredi 306d123d8e1SMiklos Szeredi buf += reclen; 307d123d8e1SMiklos Szeredi nbytes -= reclen; 308d123d8e1SMiklos Szeredi 309d123d8e1SMiklos Szeredi ret = fuse_direntplus_link(file, direntplus, attr_version); 310d123d8e1SMiklos Szeredi if (ret) 311d123d8e1SMiklos Szeredi fuse_force_forget(file, direntplus->entry_out.nodeid); 312d123d8e1SMiklos Szeredi } 313d123d8e1SMiklos Szeredi 314d123d8e1SMiklos Szeredi return 0; 315d123d8e1SMiklos Szeredi } 316d123d8e1SMiklos Szeredi 3175d7bc7e8SMiklos Szeredi static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx) 318d123d8e1SMiklos Szeredi { 31943f5098eSMiklos Szeredi int plus; 32043f5098eSMiklos Szeredi ssize_t res; 321d123d8e1SMiklos Szeredi struct page *page; 322d123d8e1SMiklos Szeredi struct inode *inode = file_inode(file); 323*fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(inode); 32443f5098eSMiklos Szeredi struct fuse_io_args ia = {}; 32543f5098eSMiklos Szeredi struct fuse_args_pages *ap = &ia.ap; 32643f5098eSMiklos Szeredi struct fuse_page_desc desc = { .length = PAGE_SIZE }; 327d123d8e1SMiklos Szeredi u64 attr_version = 0; 328d123d8e1SMiklos Szeredi bool locked; 329d123d8e1SMiklos Szeredi 330d123d8e1SMiklos Szeredi page = alloc_page(GFP_KERNEL); 33143f5098eSMiklos Szeredi if (!page) 332d123d8e1SMiklos Szeredi return -ENOMEM; 333d123d8e1SMiklos Szeredi 334d123d8e1SMiklos Szeredi plus = fuse_use_readdirplus(inode, ctx); 335cabdb4faSzhengbin ap->args.out_pages = true; 33643f5098eSMiklos Szeredi ap->num_pages = 1; 33743f5098eSMiklos Szeredi ap->pages = &page; 33843f5098eSMiklos Szeredi ap->descs = &desc; 339d123d8e1SMiklos Szeredi if (plus) { 340*fcee216bSMax Reitz attr_version = fuse_get_attr_version(fm->fc); 34143f5098eSMiklos Szeredi fuse_read_args_fill(&ia, file, ctx->pos, PAGE_SIZE, 342d123d8e1SMiklos Szeredi FUSE_READDIRPLUS); 343d123d8e1SMiklos Szeredi } else { 34443f5098eSMiklos Szeredi fuse_read_args_fill(&ia, file, ctx->pos, PAGE_SIZE, 345d123d8e1SMiklos Szeredi FUSE_READDIR); 346d123d8e1SMiklos Szeredi } 347d123d8e1SMiklos Szeredi locked = fuse_lock_inode(inode); 348*fcee216bSMax Reitz res = fuse_simple_request(fm, &ap->args); 349d123d8e1SMiklos Szeredi fuse_unlock_inode(inode, locked); 35043f5098eSMiklos Szeredi if (res >= 0) { 35143f5098eSMiklos Szeredi if (!res) { 35269e34551SMiklos Szeredi struct fuse_file *ff = file->private_data; 35369e34551SMiklos Szeredi 35469e34551SMiklos Szeredi if (ff->open_flags & FOPEN_CACHE_DIR) 35569e34551SMiklos Szeredi fuse_readdir_cache_end(file, ctx->pos); 35669e34551SMiklos Szeredi } else if (plus) { 35743f5098eSMiklos Szeredi res = parse_dirplusfile(page_address(page), res, 358d123d8e1SMiklos Szeredi file, ctx, attr_version); 359d123d8e1SMiklos Szeredi } else { 36043f5098eSMiklos Szeredi res = parse_dirfile(page_address(page), res, file, 361d123d8e1SMiklos Szeredi ctx); 362d123d8e1SMiklos Szeredi } 363d123d8e1SMiklos Szeredi } 364d123d8e1SMiklos Szeredi 365d123d8e1SMiklos Szeredi __free_page(page); 366d123d8e1SMiklos Szeredi fuse_invalidate_atime(inode); 36743f5098eSMiklos Szeredi return res; 368d123d8e1SMiklos Szeredi } 3695d7bc7e8SMiklos Szeredi 3705d7bc7e8SMiklos Szeredi enum fuse_parse_result { 3715d7bc7e8SMiklos Szeredi FOUND_ERR = -1, 3725d7bc7e8SMiklos Szeredi FOUND_NONE = 0, 3735d7bc7e8SMiklos Szeredi FOUND_SOME, 3745d7bc7e8SMiklos Szeredi FOUND_ALL, 3755d7bc7e8SMiklos Szeredi }; 3765d7bc7e8SMiklos Szeredi 3775d7bc7e8SMiklos Szeredi static enum fuse_parse_result fuse_parse_cache(struct fuse_file *ff, 3785d7bc7e8SMiklos Szeredi void *addr, unsigned int size, 3795d7bc7e8SMiklos Szeredi struct dir_context *ctx) 3805d7bc7e8SMiklos Szeredi { 3815d7bc7e8SMiklos Szeredi unsigned int offset = ff->readdir.cache_off & ~PAGE_MASK; 3825d7bc7e8SMiklos Szeredi enum fuse_parse_result res = FOUND_NONE; 3835d7bc7e8SMiklos Szeredi 3845d7bc7e8SMiklos Szeredi WARN_ON(offset >= size); 3855d7bc7e8SMiklos Szeredi 3865d7bc7e8SMiklos Szeredi for (;;) { 3875d7bc7e8SMiklos Szeredi struct fuse_dirent *dirent = addr + offset; 3885d7bc7e8SMiklos Szeredi unsigned int nbytes = size - offset; 389e5854b1cSTejun Heo size_t reclen; 3905d7bc7e8SMiklos Szeredi 3915d7bc7e8SMiklos Szeredi if (nbytes < FUSE_NAME_OFFSET || !dirent->namelen) 3925d7bc7e8SMiklos Szeredi break; 3935d7bc7e8SMiklos Szeredi 394e5854b1cSTejun Heo reclen = FUSE_DIRENT_SIZE(dirent); /* derefs ->namelen */ 395e5854b1cSTejun Heo 3965d7bc7e8SMiklos Szeredi if (WARN_ON(dirent->namelen > FUSE_NAME_MAX)) 3975d7bc7e8SMiklos Szeredi return FOUND_ERR; 3985d7bc7e8SMiklos Szeredi if (WARN_ON(reclen > nbytes)) 3995d7bc7e8SMiklos Szeredi return FOUND_ERR; 4005d7bc7e8SMiklos Szeredi if (WARN_ON(memchr(dirent->name, '/', dirent->namelen) != NULL)) 4015d7bc7e8SMiklos Szeredi return FOUND_ERR; 4025d7bc7e8SMiklos Szeredi 4035d7bc7e8SMiklos Szeredi if (ff->readdir.pos == ctx->pos) { 4045d7bc7e8SMiklos Szeredi res = FOUND_SOME; 4055d7bc7e8SMiklos Szeredi if (!dir_emit(ctx, dirent->name, dirent->namelen, 4065d7bc7e8SMiklos Szeredi dirent->ino, dirent->type)) 4075d7bc7e8SMiklos Szeredi return FOUND_ALL; 4085d7bc7e8SMiklos Szeredi ctx->pos = dirent->off; 4095d7bc7e8SMiklos Szeredi } 4105d7bc7e8SMiklos Szeredi ff->readdir.pos = dirent->off; 4115d7bc7e8SMiklos Szeredi ff->readdir.cache_off += reclen; 4125d7bc7e8SMiklos Szeredi 4135d7bc7e8SMiklos Szeredi offset += reclen; 4145d7bc7e8SMiklos Szeredi } 4155d7bc7e8SMiklos Szeredi 4165d7bc7e8SMiklos Szeredi return res; 4175d7bc7e8SMiklos Szeredi } 4185d7bc7e8SMiklos Szeredi 4197118883bSMiklos Szeredi static void fuse_rdc_reset(struct inode *inode) 4203494927eSMiklos Szeredi { 4217118883bSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 4227118883bSMiklos Szeredi 4233494927eSMiklos Szeredi fi->rdc.cached = false; 4243494927eSMiklos Szeredi fi->rdc.version++; 4253494927eSMiklos Szeredi fi->rdc.size = 0; 4263494927eSMiklos Szeredi fi->rdc.pos = 0; 4273494927eSMiklos Szeredi } 4283494927eSMiklos Szeredi 4295d7bc7e8SMiklos Szeredi #define UNCACHED 1 4305d7bc7e8SMiklos Szeredi 4315d7bc7e8SMiklos Szeredi static int fuse_readdir_cached(struct file *file, struct dir_context *ctx) 4325d7bc7e8SMiklos Szeredi { 4335d7bc7e8SMiklos Szeredi struct fuse_file *ff = file->private_data; 4345d7bc7e8SMiklos Szeredi struct inode *inode = file_inode(file); 4357118883bSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode); 4365d7bc7e8SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode); 4375d7bc7e8SMiklos Szeredi enum fuse_parse_result res; 4385d7bc7e8SMiklos Szeredi pgoff_t index; 4395d7bc7e8SMiklos Szeredi unsigned int size; 4405d7bc7e8SMiklos Szeredi struct page *page; 4415d7bc7e8SMiklos Szeredi void *addr; 4425d7bc7e8SMiklos Szeredi 4435d7bc7e8SMiklos Szeredi /* Seeked? If so, reset the cache stream */ 4445d7bc7e8SMiklos Szeredi if (ff->readdir.pos != ctx->pos) { 4455d7bc7e8SMiklos Szeredi ff->readdir.pos = 0; 4465d7bc7e8SMiklos Szeredi ff->readdir.cache_off = 0; 4475d7bc7e8SMiklos Szeredi } 4485d7bc7e8SMiklos Szeredi 4497118883bSMiklos Szeredi /* 4507118883bSMiklos Szeredi * We're just about to start reading into the cache or reading the 4517118883bSMiklos Szeredi * cache; both cases require an up-to-date mtime value. 4527118883bSMiklos Szeredi */ 4537118883bSMiklos Szeredi if (!ctx->pos && fc->auto_inval_data) { 4547118883bSMiklos Szeredi int err = fuse_update_attributes(inode, file); 4557118883bSMiklos Szeredi 4567118883bSMiklos Szeredi if (err) 4577118883bSMiklos Szeredi return err; 4587118883bSMiklos Szeredi } 4597118883bSMiklos Szeredi 4605d7bc7e8SMiklos Szeredi retry: 4615d7bc7e8SMiklos Szeredi spin_lock(&fi->rdc.lock); 4627118883bSMiklos Szeredi retry_locked: 4635d7bc7e8SMiklos Szeredi if (!fi->rdc.cached) { 4647118883bSMiklos Szeredi /* Starting cache? Set cache mtime. */ 4657118883bSMiklos Szeredi if (!ctx->pos && !fi->rdc.size) { 4667118883bSMiklos Szeredi fi->rdc.mtime = inode->i_mtime; 467261aaba7SMiklos Szeredi fi->rdc.iversion = inode_query_iversion(inode); 4687118883bSMiklos Szeredi } 4695d7bc7e8SMiklos Szeredi spin_unlock(&fi->rdc.lock); 4705d7bc7e8SMiklos Szeredi return UNCACHED; 4715d7bc7e8SMiklos Szeredi } 4723494927eSMiklos Szeredi /* 4737118883bSMiklos Szeredi * When at the beginning of the directory (i.e. just after opendir(3) or 4747118883bSMiklos Szeredi * rewinddir(3)), then need to check whether directory contents have 4757118883bSMiklos Szeredi * changed, and reset the cache if so. 4767118883bSMiklos Szeredi */ 4777118883bSMiklos Szeredi if (!ctx->pos) { 478261aaba7SMiklos Szeredi if (inode_peek_iversion(inode) != fi->rdc.iversion || 479261aaba7SMiklos Szeredi !timespec64_equal(&fi->rdc.mtime, &inode->i_mtime)) { 4807118883bSMiklos Szeredi fuse_rdc_reset(inode); 4817118883bSMiklos Szeredi goto retry_locked; 4827118883bSMiklos Szeredi } 4837118883bSMiklos Szeredi } 4847118883bSMiklos Szeredi 4857118883bSMiklos Szeredi /* 4863494927eSMiklos Szeredi * If cache version changed since the last getdents() call, then reset 4873494927eSMiklos Szeredi * the cache stream. 4883494927eSMiklos Szeredi */ 4893494927eSMiklos Szeredi if (ff->readdir.version != fi->rdc.version) { 4903494927eSMiklos Szeredi ff->readdir.pos = 0; 4913494927eSMiklos Szeredi ff->readdir.cache_off = 0; 4923494927eSMiklos Szeredi } 4933494927eSMiklos Szeredi /* 4943494927eSMiklos Szeredi * If at the beginning of the cache, than reset version to 4953494927eSMiklos Szeredi * current. 4963494927eSMiklos Szeredi */ 4973494927eSMiklos Szeredi if (ff->readdir.pos == 0) 4983494927eSMiklos Szeredi ff->readdir.version = fi->rdc.version; 4993494927eSMiklos Szeredi 5005d7bc7e8SMiklos Szeredi WARN_ON(fi->rdc.size < ff->readdir.cache_off); 5015d7bc7e8SMiklos Szeredi 5025d7bc7e8SMiklos Szeredi index = ff->readdir.cache_off >> PAGE_SHIFT; 5035d7bc7e8SMiklos Szeredi 5045d7bc7e8SMiklos Szeredi if (index == (fi->rdc.size >> PAGE_SHIFT)) 5055d7bc7e8SMiklos Szeredi size = fi->rdc.size & ~PAGE_MASK; 5065d7bc7e8SMiklos Szeredi else 5075d7bc7e8SMiklos Szeredi size = PAGE_SIZE; 5085d7bc7e8SMiklos Szeredi spin_unlock(&fi->rdc.lock); 5095d7bc7e8SMiklos Szeredi 5105d7bc7e8SMiklos Szeredi /* EOF? */ 5115d7bc7e8SMiklos Szeredi if ((ff->readdir.cache_off & ~PAGE_MASK) == size) 5125d7bc7e8SMiklos Szeredi return 0; 5135d7bc7e8SMiklos Szeredi 5145d7bc7e8SMiklos Szeredi page = find_get_page_flags(file->f_mapping, index, 5155d7bc7e8SMiklos Szeredi FGP_ACCESSED | FGP_LOCK); 5163494927eSMiklos Szeredi spin_lock(&fi->rdc.lock); 5175d7bc7e8SMiklos Szeredi if (!page) { 5185d7bc7e8SMiklos Szeredi /* 5195d7bc7e8SMiklos Szeredi * Uh-oh: page gone missing, cache is useless 5205d7bc7e8SMiklos Szeredi */ 5213494927eSMiklos Szeredi if (fi->rdc.version == ff->readdir.version) 5227118883bSMiklos Szeredi fuse_rdc_reset(inode); 5237118883bSMiklos Szeredi goto retry_locked; 5245d7bc7e8SMiklos Szeredi } 5255d7bc7e8SMiklos Szeredi 5263494927eSMiklos Szeredi /* Make sure it's still the same version after getting the page. */ 5273494927eSMiklos Szeredi if (ff->readdir.version != fi->rdc.version) { 5283494927eSMiklos Szeredi spin_unlock(&fi->rdc.lock); 5293494927eSMiklos Szeredi unlock_page(page); 5303494927eSMiklos Szeredi put_page(page); 5313494927eSMiklos Szeredi goto retry; 5323494927eSMiklos Szeredi } 5333494927eSMiklos Szeredi spin_unlock(&fi->rdc.lock); 5343494927eSMiklos Szeredi 5353494927eSMiklos Szeredi /* 5363494927eSMiklos Szeredi * Contents of the page are now protected against changing by holding 5373494927eSMiklos Szeredi * the page lock. 5383494927eSMiklos Szeredi */ 5395d7bc7e8SMiklos Szeredi addr = kmap(page); 5405d7bc7e8SMiklos Szeredi res = fuse_parse_cache(ff, addr, size, ctx); 5415d7bc7e8SMiklos Szeredi kunmap(page); 5425d7bc7e8SMiklos Szeredi unlock_page(page); 5435d7bc7e8SMiklos Szeredi put_page(page); 5445d7bc7e8SMiklos Szeredi 5455d7bc7e8SMiklos Szeredi if (res == FOUND_ERR) 5465d7bc7e8SMiklos Szeredi return -EIO; 5475d7bc7e8SMiklos Szeredi 5485d7bc7e8SMiklos Szeredi if (res == FOUND_ALL) 5495d7bc7e8SMiklos Szeredi return 0; 5505d7bc7e8SMiklos Szeredi 5515d7bc7e8SMiklos Szeredi if (size == PAGE_SIZE) { 5525d7bc7e8SMiklos Szeredi /* We hit end of page: skip to next page. */ 5535d7bc7e8SMiklos Szeredi ff->readdir.cache_off = ALIGN(ff->readdir.cache_off, PAGE_SIZE); 5545d7bc7e8SMiklos Szeredi goto retry; 5555d7bc7e8SMiklos Szeredi } 5565d7bc7e8SMiklos Szeredi 5575d7bc7e8SMiklos Szeredi /* 5585d7bc7e8SMiklos Szeredi * End of cache reached. If found position, then we are done, otherwise 5595d7bc7e8SMiklos Szeredi * need to fall back to uncached, since the position we were looking for 5605d7bc7e8SMiklos Szeredi * wasn't in the cache. 5615d7bc7e8SMiklos Szeredi */ 5625d7bc7e8SMiklos Szeredi return res == FOUND_SOME ? 0 : UNCACHED; 5635d7bc7e8SMiklos Szeredi } 5645d7bc7e8SMiklos Szeredi 5655d7bc7e8SMiklos Szeredi int fuse_readdir(struct file *file, struct dir_context *ctx) 5665d7bc7e8SMiklos Szeredi { 5675d7bc7e8SMiklos Szeredi struct fuse_file *ff = file->private_data; 5685d7bc7e8SMiklos Szeredi struct inode *inode = file_inode(file); 5695d7bc7e8SMiklos Szeredi int err; 5705d7bc7e8SMiklos Szeredi 5715d7bc7e8SMiklos Szeredi if (is_bad_inode(inode)) 5725d7bc7e8SMiklos Szeredi return -EIO; 5735d7bc7e8SMiklos Szeredi 5745d7bc7e8SMiklos Szeredi mutex_lock(&ff->readdir.lock); 5755d7bc7e8SMiklos Szeredi 5765d7bc7e8SMiklos Szeredi err = UNCACHED; 5775d7bc7e8SMiklos Szeredi if (ff->open_flags & FOPEN_CACHE_DIR) 5785d7bc7e8SMiklos Szeredi err = fuse_readdir_cached(file, ctx); 5795d7bc7e8SMiklos Szeredi if (err == UNCACHED) 5805d7bc7e8SMiklos Szeredi err = fuse_readdir_uncached(file, ctx); 5815d7bc7e8SMiklos Szeredi 5825d7bc7e8SMiklos Szeredi mutex_unlock(&ff->readdir.lock); 5835d7bc7e8SMiklos Szeredi 5845d7bc7e8SMiklos Szeredi return err; 5855d7bc7e8SMiklos Szeredi } 586