/* * iterate through the data blob that lists the contents of an AFS directory */ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, filldir_t filldir, struct key *key) { union afs_dir_block *dblock; struct afs_dir_page *dbuf; struct page *page; unsigned blkoff, limit; int ret; _enter("{%lu},%u,,", dir->i_ino, *fpos); if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dir)->flags)) { _leave(" = -ESTALE"); return -ESTALE; } /* round the file position up to the next entry boundary */ *fpos += sizeof(union afs_dirent) - 1; *fpos &= ~(sizeof(union afs_dirent) - 1); /* walk through the blocks in sequence */ ret = 0; while (*fpos < dir->i_size) { blkoff = *fpos & ~(sizeof(union afs_dir_block) - 1); /* fetch the appropriate page from the directory */ page = afs_dir_get_page(dir, blkoff / PAGE_SIZE, key); if (IS_ERR(page)) { ret = PTR_ERR(page); break; } limit = blkoff & ~(PAGE_SIZE - 1); dbuf = page_address(page); /* deal with the individual blocks stashed on this page */ do { dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) / sizeof(union afs_dir_block)]; ret = afs_dir_iterate_block(fpos, dblock, blkoff, cookie, filldir); if (ret != 1) { afs_dir_put_page(page); goto out; } blkoff += sizeof(union afs_dir_block); } while (*fpos < dir->i_size && blkoff < limit); afs_dir_put_page(page); ret = 0; } out: _leave(" = %d", ret); return ret; }
/* * get a page into the pagecache */ static struct page *afs_dir_get_page(struct inode *dir, unsigned long index, struct key *key) { struct page *page; struct file file = { .private_data = key, }; _enter("{%lu},%lu", dir->i_ino, index); page = read_mapping_page(dir->i_mapping, index, &file); if (!IS_ERR(page)) { kmap(page); if (!PageChecked(page)) afs_dir_check_page(dir, page); if (PageError(page)) goto fail; } return page; fail: afs_dir_put_page(page); _leave(" = -EIO"); return ERR_PTR(-EIO); }
/* * get a page into the pagecache */ static struct page *afs_dir_get_page(struct inode *dir, unsigned long index) { struct page *page; _enter("{%lu},%lu", dir->i_ino, index); page = read_mapping_page(dir->i_mapping, index, NULL); if (!IS_ERR(page)) { kmap(page); if (!PageChecked(page)) afs_dir_check_page(dir, page); if (PageError(page)) goto fail; } return page; fail: afs_dir_put_page(page); return ERR_PTR(-EIO); } /* end afs_dir_get_page() */
/* * get a page into the pagecache */ static struct page *afs_dir_get_page(struct inode *dir, unsigned long index, struct key *key) { struct page *page; _enter("{%lu},%lu", dir->i_ino, index); page = read_cache_page(dir->i_mapping, index, afs_page_filler, key); if (!IS_ERR(page)) { kmap(page); if (unlikely(!PageChecked(page))) { if (PageError(page) || !afs_dir_check_page(dir, page)) goto fail; } } return page; fail: afs_dir_put_page(page); _leave(" = -EIO"); return ERR_PTR(-EIO); }
/* * get a page into the pagecache */ static struct page *afs_dir_get_page(struct inode *dir, unsigned long index) { struct page *page; _enter("{%lu},%lu",dir->i_ino,index); page = read_cache_page(dir->i_mapping,index, (filler_t*)dir->i_mapping->a_ops->readpage,NULL); if (!IS_ERR(page)) { wait_on_page_locked(page); kmap(page); if (!PageUptodate(page)) goto fail; if (!PageChecked(page)) afs_dir_check_page(dir,page); if (PageError(page)) goto fail; } return page; fail: afs_dir_put_page(page); return ERR_PTR(-EIO); } /* end afs_dir_get_page() */