static int __logfs_readdir(struct file *file, void *buf, filldir_t filldir) { struct inode *dir = file->f_dentry->d_inode; loff_t pos = file->f_pos - IMPLICIT_NODES; struct page *page; struct logfs_disk_dentry *dd; int full; BUG_ON(pos < 0); for (;; pos++) { if (beyond_eof(dir, pos)) break; if (!logfs_exist_block(dir, pos)) { /* deleted dentry */ pos = dir_seek_data(dir, pos); continue; } page = read_cache_page(dir->i_mapping, pos, (filler_t *)logfs_readpage, NULL); if (IS_ERR(page)) return PTR_ERR(page); dd = kmap(page); BUG_ON(dd->namelen == 0); full = filldir(buf, (char *)dd->name, be16_to_cpu(dd->namelen), pos, be64_to_cpu(dd->ino), dd->type); kunmap(page); page_cache_release(page); if (full) break; } file->f_pos = pos + IMPLICIT_NODES; return 0; }
static int logfs_delete_dd(struct inode *dir, loff_t pos) { /* * Getting called with pos somewhere beyond eof is either a goofup * within this file or means someone maliciously edited the * (crc-protected) journal. */ BUG_ON(beyond_eof(dir, pos)); dir->i_ctime = dir->i_mtime = CURRENT_TIME; log_dir(" Delete dentry (%lx, %llx)\n", dir->i_ino, pos); return logfs_delete(dir, pos, NULL); }
/* FIXME: readdir currently has it's own dir_walk code. I don't see a good * way to combine the two copies */ static int logfs_readdir(struct file *file, struct dir_context *ctx) { struct inode *dir = file_inode(file); loff_t pos; struct page *page; struct logfs_disk_dentry *dd; if (ctx->pos < 0) return -EINVAL; if (!dir_emit_dots(file, ctx)) return 0; pos = ctx->pos - 2; BUG_ON(pos < 0); for (;; pos++, ctx->pos++) { bool full; if (beyond_eof(dir, pos)) break; if (!logfs_exist_block(dir, pos)) { /* deleted dentry */ pos = dir_seek_data(dir, pos); continue; } page = read_cache_page(dir->i_mapping, pos, (filler_t *)logfs_readpage, NULL); if (IS_ERR(page)) return PTR_ERR(page); dd = kmap(page); BUG_ON(dd->namelen == 0); full = !dir_emit(ctx, (char *)dd->name, be16_to_cpu(dd->namelen), be64_to_cpu(dd->ino), dd->type); kunmap(page); page_cache_release(page); if (full) break; } return 0; }
static struct page *logfs_get_dd_page(struct inode *dir, struct dentry *dentry) { struct qstr *name = &dentry->d_name; struct page *page; struct logfs_disk_dentry *dd; u32 hash = hash_32(name->name, name->len, 0); pgoff_t index; int round; if (name->len > LOGFS_MAX_NAMELEN) return ERR_PTR(-ENAMETOOLONG); for (round = 0; round < 20; round++) { index = hash_index(hash, round); if (beyond_eof(dir, index)) return NULL; if (!logfs_exist_block(dir, index)) continue; page = read_cache_page(dir->i_mapping, index, (filler_t *)logfs_readpage, NULL); if (IS_ERR(page)) return page; dd = kmap_atomic(page, KM_USER0); BUG_ON(dd->namelen == 0); if (name->len != be16_to_cpu(dd->namelen) || memcmp(name->name, dd->name, name->len)) { kunmap_atomic(dd, KM_USER0); page_cache_release(page); continue; } kunmap_atomic(dd, KM_USER0); return page; } return NULL; }