-static struct dentry *
- yaffs2_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
-{
- return generic_fh_to_parent(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode);
-}
-
-struct dentry *yaffs2_get_parent(struct dentry *dentry)
-{
-
- struct super_block *sb = dentry->d_inode->i_sb;
- struct dentry *parent = ERR_PTR(-ENOENT);
- struct inode *inode;
- unsigned long parent_ino;
- struct yaffs_obj *d_obj;
- struct yaffs_obj *parent_obj;
-
- d_obj = yaffs_inode_to_obj(dentry->d_inode);
-
- if (d_obj) {
- parent_obj = d_obj->parent;
- if (parent_obj) {
- parent_ino = yaffs_get_obj_inode(parent_obj);
- inode = Y_IGET(sb, parent_ino);
-
- if (IS_ERR(inode)) {
- parent = ERR_CAST(inode);
- } else {
- parent = d_obtain_alias(inode);
- if (!IS_ERR(parent)) {
- parent = ERR_PTR(-ENOMEM);
- iput(inode);
- }
- }
- }
- }
-
- return parent;
-}
-
-/* Just declare a zero structure as a NULL value implies
- * using the default functions of exportfs.
- */
-
-static struct export_operations yaffs_export_ops =
-{
- .fh_to_dentry = yaffs2_fh_to_dentry,
- .fh_to_parent = yaffs2_fh_to_parent,
- .get_parent = yaffs2_get_parent,
-} ;
-
-#endif
-
-/*-----------------------------------------------------------------*/
-/* Directory search context allows us to unlock access to yaffs during
- * filldir without causing problems with the directory being modified.
- * This is similar to the tried and tested mechanism used in yaffs direct.
- *
- * A search context iterates along a doubly linked list of siblings in the
- * directory. If the iterating object is deleted then this would corrupt
- * the list iteration, likely causing a crash. The search context avoids
- * this by using the remove_obj_fn to move the search context to the
- * next object before the object is deleted.
- *
- * Many readdirs (and thus seach conexts) may be alive simulateously so
- * each struct yaffs_dev has a list of these.
- *
- * A seach context lives for the duration of a readdir.
- *
- * All these functions must be called while yaffs is locked.
- */
-
-struct yaffs_search_context {
- struct yaffs_dev *dev;
- struct yaffs_obj *dir_obj;
- struct yaffs_obj *next_return;
- struct list_head others;
-};
-
-/*
- * yaffs_new_search() creates a new search context, initialises it and
- * adds it to the device's search context list.
- *
- * Called at start of readdir.
- */
-static struct yaffs_search_context * yaffs_new_search(struct yaffs_obj *dir)
-{
- struct yaffs_dev *dev = dir->my_dev;
- struct yaffs_search_context *sc = YMALLOC(sizeof(struct yaffs_search_context));
- if(sc){
- sc->dir_obj = dir;
- sc->dev = dev;
- if( list_empty(&sc->dir_obj->variant.dir_variant.children))
- sc->next_return = NULL;
- else
- sc->next_return = list_entry(
- dir->variant.dir_variant.children.next,
- struct yaffs_obj,siblings);
- INIT_LIST_HEAD(&sc->others);
- list_add(&sc->others,&(yaffs_dev_to_lc(dev)->search_contexts));
- }
- return sc;
-}
-
-/*
- * yaffs_search_end() disposes of a search context and cleans up.
- */
-static void yaffs_search_end(struct yaffs_search_context * sc)
-{
- if(sc){
- list_del(&sc->others);
- YFREE(sc);
- }
-}
-
-/*
- * yaffs_search_advance() moves a search context to the next object.
- * Called when the search iterates or when an object removal causes
- * the search context to be moved to the next object.
- */
-static void yaffs_search_advance(struct yaffs_search_context *sc)
-{
- if(!sc)
- return;
-
- if( sc->next_return == NULL ||
- list_empty(&sc->dir_obj->variant.dir_variant.children))
- sc->next_return = NULL;
- else {
- struct list_head *next = sc->next_return->siblings.next;
-
- if( next == &sc->dir_obj->variant.dir_variant.children)
- sc->next_return = NULL; /* end of list */
- else
- sc->next_return = list_entry(next,struct yaffs_obj,siblings);
- }
-}
-
-/*
- * yaffs_remove_obj_callback() is called when an object is unlinked.
- * We check open search contexts and advance any which are currently
- * on the object being iterated.
- */
-static void yaffs_remove_obj_callback(struct yaffs_obj *obj)
-{
-
- struct list_head *i;
- struct yaffs_search_context *sc;
- struct list_head *search_contexts = &(yaffs_dev_to_lc(obj->my_dev)->search_contexts);
-
-
- /* Iterate through the directory search contexts.
- * If any are currently on the object being removed, then advance
- * the search context to the next object to prevent a hanging pointer.
- */
- list_for_each(i, search_contexts) {
- if (i) {
- sc = list_entry(i, struct yaffs_search_context,others);
- if(sc->next_return == obj)
- yaffs_search_advance(sc);
- }
- }
-
-}
-
-
-/*-----------------------------------------------------------------*/
-
-static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
- int buflen)
-{
- unsigned char *alias;
- int ret;
-
- struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
-
- yaffs_gross_lock(dev);
-
- alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
-
- yaffs_gross_unlock(dev);
-
- if (!alias)
- return -ENOMEM;
-
- ret = vfs_readlink(dentry, buffer, buflen, alias);
- kfree(alias);
- return ret;
-}
-
-#if (YAFFS_NEW_FOLLOW_LINK == 1)
-static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
-{
- void *ret;
-#else
-static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
-{
- int ret
-#endif
- unsigned char *alias;
- int ret_int = 0;
- struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
-
- yaffs_gross_lock(dev);
-
- alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
- yaffs_gross_unlock(dev);
-
- if (!alias) {
- ret_int = -ENOMEM;
- goto out;
- }
-
-#if (YAFFS_NEW_FOLLOW_LINK == 1)
- nd_set_link(nd, alias);
- ret = alias;
-out:
- if(ret_int)
- ret = ERR_PTR(ret_int);
- return ret;
-#else
- ret = vfs_follow_link(nd, alias);
- kfree(alias);
-out:
- if(ret_int)
- ret = ret_int;
- return ret;
-#endif
-}
-
-#if (YAFFS_NEW_FOLLOW_LINK == 1)
-void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias) {
- kfree(alias);
-}
-#endif
-
-struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
- struct yaffs_obj *obj);
-
-/*
- * Lookup is used to find objects in the fs
- */
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
-
-static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
- struct nameidata *n)
-#else
-static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
-#endif
-{
- struct yaffs_obj *obj;
- struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
-
- struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev;
-
- if(current != yaffs_dev_to_lc(dev)->readdir_process)
- yaffs_gross_lock(dev);
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_lookup for %d:%s\n"),
- yaffs_inode_to_obj(dir)->obj_id, dentry->d_name.name));
-
- obj = yaffs_find_by_name(yaffs_inode_to_obj(dir),
- dentry->d_name.name);
-
- obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */
-
- /* Can't hold gross lock when calling yaffs_get_inode() */
- if(current != yaffs_dev_to_lc(dev)->readdir_process)
- yaffs_gross_unlock(dev);
-
- if (obj) {
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_lookup found %d\n"), obj->obj_id));
-
- inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
-
- if (inode) {
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_loookup dentry \n")));
-/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
- * d_add even if NULL inode */
-#if 0
- /*dget(dentry); // try to solve directory bug */
- d_add(dentry, inode);
-
- /* return dentry; */
- return NULL;
-#endif
- }
-
- } else {
- T(YAFFS_TRACE_OS,(TSTR("yaffs_lookup not found\n")));
-
- }
-
-/* added NCB for 2.5/6 compatability - forces add even if inode is
- * NULL which creates dentry hash */
- d_add(dentry, inode);
-
- return NULL;
-}
-
-
-#ifdef YAFFS_HAS_PUT_INODE
-
-/* For now put inode is just for debugging
- * Put inode is called when the inode **structure** is put.
- */
-static void yaffs_put_inode(struct inode *inode)
-{
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_put_inode: ino %d, count %d\n"), (int)inode->i_ino,
- atomic_read(&inode->i_count)));
-
-}
-#endif
-
-
-static void yaffs_unstitch_obj(struct inode *inode, struct yaffs_obj *obj)
-{
- /* Clear the association between the inode and
- * the struct yaffs_obj.
- */
- obj->my_inode = NULL;
- yaffs_inode_to_obj_lv(inode) = NULL;
-
- /* If the object freeing was deferred, then the real
- * free happens now.
- * This should fix the inode inconsistency problem.
- */
- yaffs_handle_defered_free(obj);
-}
-
-#ifdef YAFFS_HAS_EVICT_INODE
-/* yaffs_evict_inode combines into one operation what was previously done in
- * yaffs_clear_inode() and yaffs_delete_inode()
- *
- */
-static void yaffs_evict_inode( struct inode *inode)
-{
- struct yaffs_obj *obj;
- struct yaffs_dev *dev;
- int deleteme = 0;
-
- obj = yaffs_inode_to_obj(inode);
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_evict_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
- atomic_read(&inode->i_count),
- obj ? "object exists" : "null object"));
-
- if (!inode->i_nlink && !is_bad_inode(inode))
- deleteme = 1;
- truncate_inode_pages(&inode->i_data,0);
- end_writeback(inode);
-
- if(deleteme && obj){
- dev = obj->my_dev;
- yaffs_gross_lock(dev);
- yaffs_del_obj(obj);
- yaffs_gross_unlock(dev);
- }
- if (obj) {
- dev = obj->my_dev;
- yaffs_gross_lock(dev);
- yaffs_unstitch_obj(inode,obj);
- yaffs_gross_unlock(dev);
- }
-
-
-}
-#else
-
-/* clear is called to tell the fs to release any per-inode data it holds.
- * The object might still exist on disk and is just being thrown out of the cache
- * or else the object has actually been deleted and we're being called via
- * the chain
- * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
- */
-
-static void yaffs_clear_inode(struct inode *inode)
-{
- struct yaffs_obj *obj;
- struct yaffs_dev *dev;
-
- obj = yaffs_inode_to_obj(inode);
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_clear_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
- atomic_read(&inode->i_count),
- obj ? "object exists" : "null object"));
-
- if (obj) {
- dev = obj->my_dev;
- yaffs_gross_lock(dev);
- yaffs_unstitch_obj(inode,obj);
- yaffs_gross_unlock(dev);
- }
-
-}
-
-/* delete is called when the link count is zero and the inode
- * is put (ie. nobody wants to know about it anymore, time to
- * delete the file).
- * NB Must call clear_inode()
- */
-static void yaffs_delete_inode(struct inode *inode)
-{
- struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
- struct yaffs_dev *dev;
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_delete_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
- atomic_read(&inode->i_count),
- obj ? "object exists" : "null object"));
-
- if (obj) {
- dev = obj->my_dev;
- yaffs_gross_lock(dev);
- yaffs_del_obj(obj);
- yaffs_gross_unlock(dev);
- }
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
- truncate_inode_pages(&inode->i_data, 0);
-#endif
- clear_inode(inode);
-}
-#endif
-
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
-static int yaffs_file_flush(struct file *file, fl_owner_t id)
-#else
-static int yaffs_file_flush(struct file *file)
-#endif
-{
- struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry);
-
- struct yaffs_dev *dev = obj->my_dev;
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_file_flush object %d (%s)\n"), obj->obj_id,
- obj->dirty ? "dirty" : "clean"));
-
- yaffs_gross_lock(dev);
-
- yaffs_flush_file(obj, 1, 0);
-
- yaffs_gross_unlock(dev);
-
- return 0;
-}
-
-static int yaffs_readpage_nolock(struct file *f, struct page *pg)
-{
- /* Lifted from jffs2 */
-
- struct yaffs_obj *obj;
- unsigned char *pg_buf;
- int ret;
-
- struct yaffs_dev *dev;
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_readpage_nolock at %08x, size %08x\n"),
- (unsigned)(pg->index << PAGE_CACHE_SHIFT),
- (unsigned)PAGE_CACHE_SIZE));
-
- obj = yaffs_dentry_to_obj(f->f_dentry);
-
- dev = obj->my_dev;
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
- BUG_ON(!PageLocked(pg));
-#else
- if (!PageLocked(pg))
- PAGE_BUG(pg);
-#endif
-
- pg_buf = kmap(pg);
- /* FIXME: Can kmap fail? */
-
- yaffs_gross_lock(dev);
-
- ret = yaffs_file_rd(obj, pg_buf,
- pg->index << PAGE_CACHE_SHIFT,
- PAGE_CACHE_SIZE);
-
- yaffs_gross_unlock(dev);
-
- if (ret >= 0)
- ret = 0;
-
- if (ret) {
- ClearPageUptodate(pg);
- SetPageError(pg);
- } else {
- SetPageUptodate(pg);
- ClearPageError(pg);