--- a/fs/yaffs2/yaffs_vfs.c +++ b/fs/yaffs2/yaffs_vfs.c @@ -1701,6 +1701,110 @@ static void yaffs_remove_obj_callback(st /*-----------------------------------------------------------------*/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) +static int yaffs_readdir(struct file *file, struct dir_context *ctx) +{ + struct yaffs_obj *obj; + struct yaffs_dev *dev; + struct yaffs_search_context *sc; + struct inode *inode = file->f_dentry->d_inode; + unsigned long offset, curoffs; + struct yaffs_obj *l; + int ret_val = 0; + + char name[YAFFS_MAX_NAME_LENGTH + 1]; + + obj = yaffs_dentry_to_obj(file->f_dentry); + dev = obj->my_dev; + + yaffs_gross_lock(dev); + + yaffs_dev_to_lc(dev)->readdir_process = current; + + offset = ctx->pos; + + sc = yaffs_new_search(obj); + if (!sc) { + ret_val = -ENOMEM; + goto out; + } + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_readdir: starting at %d", (int)offset); + + if (offset == 0) { + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_readdir: entry . ino %d", + (int)inode->i_ino); + yaffs_gross_unlock(dev); + if (!dir_emit_dot(file, ctx)) { + yaffs_gross_lock(dev); + goto out; + } + yaffs_gross_lock(dev); + offset++; + ctx->pos++; + } + if (offset == 1) { + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_readdir: entry .. ino %d", + (int)file->f_dentry->d_parent->d_inode->i_ino); + yaffs_gross_unlock(dev); + if (!dir_emit_dotdot(file, ctx)) { + yaffs_gross_lock(dev); + goto out; + } + yaffs_gross_lock(dev); + offset++; + ctx->pos++; + } + + curoffs = 1; + + /* If the directory has changed since the open or last call to + readdir, rewind to after the 2 canned entries. */ + if (file->f_version != inode->i_version) { + offset = 2; + ctx->pos = offset; + file->f_version = inode->i_version; + } + + while (sc->next_return) { + curoffs++; + l = sc->next_return; + if (curoffs >= offset) { + int this_inode = yaffs_get_obj_inode(l); + int this_type = yaffs_get_obj_type(l); + + yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1); + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_readdir: %s inode %d", + name, yaffs_get_obj_inode(l)); + + yaffs_gross_unlock(dev); + + if (!dir_emit(ctx, name, strlen(name), + this_inode, this_type) < 0) { + yaffs_gross_lock(dev); + goto out; + } + + yaffs_gross_lock(dev); + + offset++; + ctx->pos++; + } + yaffs_search_advance(sc); + } + +out: + yaffs_search_end(sc); + yaffs_dev_to_lc(dev)->readdir_process = NULL; + yaffs_gross_unlock(dev); + + return ret_val; +} +#else static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) { struct yaffs_obj *obj; @@ -1807,10 +1911,15 @@ out: return ret_val; } +#endif static const struct file_operations yaffs_dir_operations = { .read = generic_read_dir, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) + .iterate = yaffs_readdir, +#else .readdir = yaffs_readdir, +#endif .fsync = yaffs_sync_object, .llseek = generic_file_llseek, };