diff options
Diffstat (limited to 'libglusterfs/src/inode.c')
| -rw-r--r-- | libglusterfs/src/inode.c | 1174 | 
1 files changed, 1174 insertions, 0 deletions
diff --git a/libglusterfs/src/inode.c b/libglusterfs/src/inode.c new file mode 100644 index 00000000000..6c527fc75a3 --- /dev/null +++ b/libglusterfs/src/inode.c @@ -0,0 +1,1174 @@ +/* +   Copyright (c) 2007, 2008 Z RESEARCH, Inc. <http://www.zresearch.com> +   This file is part of GlusterFS. + +   GlusterFS is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published +   by the Free Software Foundation; either version 3 of the License, +   or (at your option) any later version. + +   GlusterFS is distributed in the hope that it will be useful, but +   WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program.  If not, see +   <http://www.gnu.org/licenses/>. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "inode.h" +#include "common-utils.h" +#include <pthread.h> +#include <sys/types.h> +#include <stdint.h> +#include "list.h" +#include <time.h> +#include <assert.h> + +/* TODO:  +   move latest accessed dentry to list_head of inode +*/ + +static inode_t * +__inode_unref (inode_t *inode); + +static int +inode_table_prune (inode_table_t *table); + +static int +hash_name (ino_t par, +           const char *name, +           int mod) +{ +        int hash = 0; +        int ret = 0; + +        hash = *name; +        if (hash) { +                for (name += 1; *name != '\0'; name++) { +                        hash = (hash << 5) - hash + *name; +                } +        } +        ret = (hash + par) % mod; + +        return ret; +} + + +static int +hash_inode (ino_t ino, +            int mod) +{ +        int hash = 0; + +        hash = ino % mod; + +        return hash; +} + + +static void +__dentry_hash (dentry_t *dentry) +{ +        inode_table_t   *table = NULL; +        int              hash = 0; + +        table = dentry->inode->table; +        hash = hash_name (dentry->parent->ino, dentry->name, +                          table->hashsize); + +        list_del_init (&dentry->hash); +        list_add (&dentry->hash, &table->name_hash[hash]); + +        list_del_init (&dentry->parent_list); +        list_add (&dentry->parent_list, &dentry->parent->child_list); +	 +	gf_log (table->name, GF_LOG_DEBUG, +		"dentry hashed %s (%"PRId64")", +		dentry->name, dentry->inode->ino); +} + + +static int +__is_dentry_hashed (dentry_t *dentry) +{ +        return !list_empty (&dentry->hash); +} + + +static void +__dentry_unhash (dentry_t *dentry) +{ +        list_del_init (&dentry->hash); +	 +	gf_log (dentry->inode->table->name, GF_LOG_DEBUG, +		"dentry unhashed %s (%"PRId64")", +		dentry->name, dentry->inode->ino); +} + + +static void +__dentry_unset (dentry_t *dentry) +{ +        __dentry_unhash (dentry); + +        list_del_init (&dentry->inode_list); + +	gf_log (dentry->inode->table->name, GF_LOG_DEBUG, +		"unset dentry %s (%"PRId64")", +		dentry->name, dentry->inode->ino); + +        if (dentry->name) +                FREE (dentry->name); + +        if (dentry->parent) { +                list_del_init (&dentry->parent_list); +                __inode_unref (dentry->parent); +                dentry->parent = NULL; +        } + +        FREE (dentry); +} + + +static void +__inode_unhash (inode_t *inode) +{ +        list_del_init (&inode->hash); +} + + +static int +__is_inode_hashed (inode_t *inode) +{ +        return !list_empty (&inode->hash); +} + + +static void +__inode_hash (inode_t *inode) +{ +        inode_table_t *table = NULL; +        int            hash = 0; + +        table = inode->table; +        hash = hash_inode (inode->ino, table->hashsize); + +        list_del_init (&inode->hash); +        list_add (&inode->hash, &table->inode_hash[hash]); +} + + +static inode_t * +__inode_search (inode_table_t *table, +                ino_t ino) +{ +        int  hash = 0; +        inode_t  *inode = NULL; +        inode_t  *tmp = NULL; + +        hash = hash_inode (ino, table->hashsize); + +        list_for_each_entry (tmp, &table->inode_hash[hash], hash) { +                if (tmp->ino == ino) { +                        inode = tmp; +                        break; +                } +        } + +        return inode; +} + + +static dentry_t * +__dentry_search_for_inode (inode_t *inode, +                           ino_t par, +                           const char *name) +{ +        dentry_t *dentry = NULL; +        dentry_t *tmp = NULL; + +        list_for_each_entry (tmp, &inode->dentry_list, inode_list) { +                if (tmp->parent->ino == par && !strcmp (tmp->name, name)) { +                        dentry = tmp; +                        break; +                } +        } + +        return dentry; +} + + +static dentry_t * +__dentry_search (inode_table_t *table, +                 ino_t par, +                 const char *name) +{ +        int       hash = 0; +        dentry_t *dentry = NULL; +        dentry_t *tmp = NULL; + +        hash = hash_name (par, name, table->hashsize); + +        list_for_each_entry (tmp, &table->name_hash[hash], hash) { +                if (tmp->parent->ino == par && !strcmp (tmp->name, name)) { +                        dentry = tmp; +                        break; +                } +        } + +        return dentry; +} + + +static void +__inode_destroy (inode_t *inode) +{ +	int          index = 0; +        data_pair_t *pair = NULL; +        xlator_t    *xl = NULL; + +        if (!inode->ctx) { +                goto noctx; +        } +        for (pair = inode->ctx->members_list; pair; pair = pair->next) { +                /* notify all xlators which have a context */ +                xl = xlator_search_by_name (inode->table->xl, pair->key); + +                if (!xl) { +                        gf_log (inode->table->name, GF_LOG_CRITICAL, +                                "inode(%"PRId64")->ctx has invalid key(%s)", +                                inode->ino, pair->key); +                        continue; +                } + +		if (xl->cbks->forget) +			xl->cbks->forget (xl, inode); +		else +                        gf_log (inode->table->name, GF_LOG_CRITICAL, +                                "xlator(%s) in inode(%"PRId64") no FORGET fop", +                                xl->name, inode->ino); +        } +        dict_destroy (inode->ctx); + +	if (!inode->_ctx) +		goto noctx; + +	for (index = 0; index < inode->table->xl->ctx->xl_count; index++) { +		if (inode->_ctx[index].key) { +			xl = (xlator_t *)(long)inode->_ctx[index].key; +			if (xl->cbks->forget) +				xl->cbks->forget (xl, inode); +		} +	}	 + +	FREE (inode->_ctx); +noctx: + +        if (inode->ino) +                gf_log (inode->table->name, GF_LOG_DEBUG, +                        "destroy inode(%"PRId64") [@%p]", inode->ino, inode); +   +        LOCK_DESTROY (&inode->lock); +        //  memset (inode, 0xb, sizeof (*inode)); +        FREE (inode); +} + + +static void +__inode_activate (inode_t *inode) +{ +        list_move (&inode->list, &inode->table->active); +        inode->table->active_size++; +	 +        gf_log (inode->table->name, GF_LOG_DEBUG, +                "activating inode(%"PRId64"), lru=%d/%d active=%d purge=%d", +                inode->ino, inode->table->lru_size, inode->table->lru_limit, +                inode->table->active_size, inode->table->purge_size); +} + + +static void +__inode_passivate (inode_t *inode) +{ +        dentry_t      *dentry = NULL; +        dentry_t      *t = NULL; +        inode_table_t *table = NULL; + +        table = inode->table; + +        list_move_tail (&inode->list, &inode->table->lru); +        inode->table->lru_size++; + +        gf_log (table->name, GF_LOG_DEBUG, +                "passivating inode(%"PRId64") lru=%d/%d active=%d purge=%d", +                inode->ino, table->lru_size, table->lru_limit, +                table->active_size, table->purge_size); + +        list_for_each_entry_safe (dentry, t, &inode->dentry_list, inode_list) { +                if (!__is_dentry_hashed (dentry)) +                        __dentry_unset (dentry); +        } +} + + +static void +__inode_retire (inode_t *inode) +{ +        dentry_t      *dentry = NULL; +        dentry_t      *t = NULL; +        inode_table_t *table = NULL; + +        table = inode->table; + +        list_move_tail (&inode->list, &inode->table->purge); +        inode->table->purge_size++; + +        gf_log (table->name, GF_LOG_DEBUG, +                "retiring inode(%"PRId64") lru=%d/%d active=%d purge=%d", +                inode->ino, table->lru_size, table->lru_limit, +                table->active_size, table->purge_size); + +        __inode_unhash (inode); +        assert (list_empty (&inode->child_list)); + +        list_for_each_entry_safe (dentry, t, &inode->dentry_list, inode_list) { +                __dentry_unset (dentry); +        } +} + + +static inode_t * +__inode_unref (inode_t *inode) +{ +        if (inode->ino == 1) +                return inode; + +        assert (inode->ref); + +        --inode->ref; + +        if (!inode->ref) { +                inode->table->active_size--; + +                if (inode->nlookup && __is_inode_hashed (inode)) +                        __inode_passivate (inode); +                else +                        __inode_retire (inode); +        } + +        return inode; +} + + +static inode_t * +__inode_ref (inode_t *inode) +{ +        if (!inode->ref) { +                inode->table->lru_size--; +                __inode_activate (inode); +        } +        inode->ref++; + +        return inode; +} + + +inode_t * +inode_unref (inode_t *inode) +{ +        inode_table_t *table = NULL; + +        table = inode->table; + +        pthread_mutex_lock (&table->lock); +        { +                inode = __inode_unref (inode); +        } +        pthread_mutex_unlock (&table->lock); + +        inode_table_prune (table); + +        return inode; +} + + +inode_t * +inode_ref (inode_t *inode) +{ +        inode_table_t *table = NULL; + +        table = inode->table; + +        pthread_mutex_lock (&table->lock); +        { +                inode = __inode_ref (inode); +        } +        pthread_mutex_unlock (&table->lock); + +        return inode; +} + + +static dentry_t * +__dentry_create (inode_t *inode, +                 inode_t *parent, +                 const char *name) +{ +        dentry_t      *newd = NULL; + +        newd = (void *) CALLOC (1, sizeof (*newd)); + +        INIT_LIST_HEAD (&newd->inode_list); +        INIT_LIST_HEAD (&newd->parent_list); +        INIT_LIST_HEAD (&newd->hash); + +        list_add (&newd->parent_list, &parent->child_list); +        newd->parent = __inode_ref (parent); +        newd->name = strdup (name); + +        list_add (&newd->inode_list, &inode->dentry_list); +        newd->inode = inode; + +        return newd; +} + + +static inode_t * +__inode_create (inode_table_t *table) +{ +        inode_t  *newi = NULL; + +        newi = (void *) CALLOC (1, sizeof (*newi)); +        if (!newi) +                return NULL; + +        newi->table = table; + +        LOCK_INIT (&newi->lock); + +        INIT_LIST_HEAD (&newi->fd_list); +        INIT_LIST_HEAD (&newi->list); +        INIT_LIST_HEAD (&newi->hash); +        INIT_LIST_HEAD (&newi->dentry_list); +        INIT_LIST_HEAD (&newi->child_list); + + +        list_add (&newi->list, &table->lru); +        table->lru_size++; + +	newi->_ctx = CALLOC (1, (sizeof (struct _inode_ctx) *  +				 table->xl->ctx->xl_count)); + +        newi->ctx = get_new_dict (); +        gf_log (table->name, GF_LOG_DEBUG, +                "create inode(%"PRId64")", newi->ino); + +        return newi; +} + + +inode_t * +inode_new (inode_table_t *table) +{ +        inode_t *inode = NULL; + +        pthread_mutex_lock (&table->lock); +        { +                inode = __inode_create (table); +                __inode_ref (inode); +        } +        pthread_mutex_unlock (&table->lock); + +        return inode; +} + + +static inode_t * +__inode_lookup (inode_t *inode) +{ +        inode->nlookup++; + +        return inode; +} + + +static inode_t * +__inode_forget (inode_t *inode, uint64_t nlookup) +{ +        assert (inode->nlookup >= nlookup); + +        inode->nlookup -= nlookup; + +        if (!nlookup) +                inode->nlookup = 0; + +        return inode; +} + + +inode_t * +inode_search (inode_table_t *table, +              ino_t ino, +              const char *name) +{ +        inode_t *inode = NULL; +        dentry_t *dentry = NULL; + +        pthread_mutex_lock (&table->lock); +        { +                if (!name) { +                        inode = __inode_search (table, ino); +                } else { +                        dentry = __dentry_search (table, ino, name); +       +                        if (dentry) +                                inode = dentry->inode; +                } +     +                if (inode) +                        __inode_ref (inode); +        } +        pthread_mutex_unlock (&table->lock); + +        return inode; +} + + +static void +__copy_dentries (inode_t *oldi, inode_t *newi) +{ +        dentry_t *dentry = NULL; +        dentry_t *newd = NULL; +        dentry_t *tmp = NULL; + +        list_for_each_entry (dentry, &oldi->dentry_list, inode_list) { +                tmp = __dentry_search_for_inode (newi, dentry->parent->ino, +                                                 dentry->name); + +                if (!tmp) { +                        newd = __dentry_create (newi, dentry->parent, +                                                dentry->name); +                } else { +                        newd = tmp; +                } + +                if (__is_dentry_hashed (dentry)) { +                        __dentry_unhash (dentry); +                        __dentry_hash (newd); +                } +        } +} + + +static void +__adopt_children (inode_t *oldi, inode_t *newi) +{ +        dentry_t *dentry = NULL; + +        list_for_each_entry (dentry, &oldi->child_list, parent_list) { +                assert (dentry->parent == oldi); +                __inode_unref (dentry->parent); +                dentry->parent = __inode_ref (newi); +        } + +        list_splice_init (&oldi->child_list, &newi->child_list); +} + + +static void +__inode_replace (inode_t *oldi, inode_t *newi) +{ +        gf_log (oldi->table->name, GF_LOG_DEBUG, +                "inode(%"PRId64") replaced (%"PRId64"", +                oldi->ino, newi->ino); + +        __copy_dentries (oldi, newi); +        __adopt_children (oldi, newi); + +        newi->nlookup    = oldi->nlookup; +        newi->generation = oldi->generation; + +        oldi->nlookup    = 0; +        oldi->generation = 0; + +        __inode_unhash (oldi); + +	if (newi->ino == 1) +		newi->table->root = newi; +} + + +static inode_t * +__inode_link (inode_t *inode, +              inode_t *parent, +              const char *name, +              struct stat *stbuf) +{ +        dentry_t      *dentry = NULL; +        dentry_t      *old_dentry = NULL; +        inode_t       *old_inode = NULL; +        inode_table_t *table = NULL; + +        table = inode->table; + +	if (inode->ino) +		assert (inode->ino == stbuf->st_ino); + +        inode->ino     = stbuf->st_ino; +        inode->st_mode = stbuf->st_mode; + +        old_inode = __inode_search (table, stbuf->st_ino); + +        if (old_inode && old_inode != inode) { +                __inode_ref (old_inode); +                __inode_replace (old_inode, inode); +                __inode_unref (old_inode); +        } +        __inode_hash (inode); + +        if (parent) { +                dentry = __dentry_search_for_inode (inode, parent->ino, name); +                if (!dentry) { +                        dentry = __dentry_create (inode, parent, name); +                } + +                old_dentry = __dentry_search (table, parent->ino, name); +                if (old_dentry) { +                        __dentry_unhash (old_dentry); +                } + +                __dentry_hash (dentry); +        } else if (inode->ino != 1) { +		gf_log (table->name, GF_LOG_ERROR, +			"child (%"PRId64") without a parent :O", inode->ino); +	} +	 +        return inode; +} + + +int +inode_link (inode_t *inode, +            inode_t *parent, +            const char *name, +            struct stat *stbuf) +{ +        inode_table_t *table = NULL; + +        table = inode->table; + +        pthread_mutex_lock (&table->lock); +        { +                inode = __inode_link (inode, parent, name, stbuf); +        } +        pthread_mutex_unlock (&table->lock); + +        inode_table_prune (table); + +        return 0; +} + + +int +inode_lookup (inode_t *inode) +{ +        inode_table_t *table = NULL; +	inode_t       *lookup_inode = NULL; + +        table = inode->table; +	lookup_inode = inode; + +        pthread_mutex_lock (&table->lock); +        { +		if (!__is_inode_hashed (inode)) { +			lookup_inode = __inode_search (table, inode->ino); +		} + +                __inode_lookup (lookup_inode); +        } +        pthread_mutex_unlock (&table->lock); + +        return 0; +} + + +int +inode_forget (inode_t *inode, uint64_t nlookup) +{ +        inode_table_t *table = NULL; +	inode_t       *forget_inode = NULL; + +        table = inode->table; +	forget_inode = inode; + +        pthread_mutex_lock (&table->lock); +        { +		if (!__is_inode_hashed (inode)) { +			forget_inode = __inode_search (table, inode->ino); +		} + +                 __inode_forget (forget_inode, nlookup); +        } +        pthread_mutex_unlock (&table->lock); + +        inode_table_prune (table); + +        return 0; +} + + +static void +__inode_unlink (inode_t *inode, +                inode_t *parent, +                const char *name) +{ +        dentry_t *dentry = NULL; + +        dentry = __dentry_search_for_inode (inode, parent->ino, name); + +	/* dentry NULL for corrupted backend */ +	if (dentry)  +		__dentry_unset (dentry); +} + +			       +void +inode_unlink (inode_t *inode, +              inode_t *parent, +              const char *name) +{ +        inode_table_t *table = NULL; +	inode_t       *unlink_inode = NULL; + +        table = inode->table; +	unlink_inode = inode; + +        pthread_mutex_lock (&table->lock); +        { +		if (!__is_inode_hashed (inode)) { +			unlink_inode = __inode_search (table, inode->ino); +		} + +                __inode_unlink (unlink_inode, parent, name); +        } +        pthread_mutex_unlock (&table->lock); + +        inode_table_prune (table); +} + + +int +inode_rename (inode_table_t *table, +              inode_t *srcdir, +              const char *srcname, +              inode_t *dstdir, +              const char *dstname, +              inode_t *inode, +              struct stat *stbuf) +{ +	dentry_t      *old_dst = NULL; +	inode_t       *rename_inode = NULL; + +	rename_inode = inode; + +        pthread_mutex_lock (&table->lock); +        { +		if (!__is_inode_hashed (inode)) { +			rename_inode = __inode_search (table, inode->ino); +		} + +		old_dst = __dentry_search (table, dstdir->ino, dstname); +		if (old_dst) +			__dentry_unset (old_dst); + +                __inode_unlink (rename_inode, srcdir, srcname); +                __inode_link (rename_inode, dstdir, dstname, stbuf); +        } +        pthread_mutex_unlock (&table->lock); + +        inode_table_prune (table); + +        return 0; +} + + +static dentry_t * +__dentry_search_arbit (inode_t *inode) +{ +	dentry_t *dentry = NULL; +	dentry_t *trav = NULL; + +	list_for_each_entry (trav, &inode->dentry_list, inode_list) { +		if (__is_dentry_hashed (trav)) { +			dentry = trav; +			break; +		} +	} + +	if (!dentry) { +		list_for_each_entry (trav, &inode->dentry_list, inode_list) { +			dentry = trav; +			break; +		} +	} + +	return dentry; +} + + +inode_t * +inode_parent (inode_t *inode, ino_t par, const char *name) +{ +        inode_t       *parent = NULL; +        inode_table_t *table = NULL; +        dentry_t      *dentry = NULL; + +        table = inode->table; + +        pthread_mutex_lock (&table->lock); +        { +                if (par && name) { +                        dentry = __dentry_search_for_inode (inode, par, name); +                } else { +                        dentry = __dentry_search_arbit (inode); +                } + +                if (dentry) +                        parent = __inode_ref (dentry->parent); +        } +        pthread_mutex_unlock (&table->lock); + +        return parent; +} + + +int32_t +inode_path (inode_t *inode,  +	    const char *name,  +	    char **bufp) +{ +        inode_table_t *table = NULL; +        dentry_t      *trav = NULL; +        size_t         i = 0, size = 0; +        int64_t        ret = 0; +        int            len = 0; +	char          *buf = NULL; +	 +        table = inode->table; + +        pthread_mutex_lock (&table->lock); +        { +                for (trav = __dentry_search_arbit (inode); trav; +                     trav = __dentry_search_arbit (trav->parent)) { +                        i ++; /* "/" */ +                        i += strlen (trav->name); +                } +		 +		if ((inode->ino != 1) && +		    (i == 0)) { +			gf_log (table->name, GF_LOG_DEBUG, +				"no dentry for non-root inode %"PRId64, +				inode->ino); +			ret = -ENOENT; +			goto unlock; +		} + +                if (name) { +                        i++; +                        i += strlen (name); +                } + +                ret = i; +		size = i + 1; +		buf = CALLOC (size, sizeof (char)); +                if (buf) { + +                        buf[size - 1] = 0; + +                        if (name) { +                                len = strlen (name); +                                strncpy (buf + (i - len), name, len); +                                buf[i-len-1] = '/'; +                                i -= (len + 1); +                        } + +                        for (trav = __dentry_search_arbit (inode); trav; +                             trav = __dentry_search_arbit (trav->parent)) { +                                len = strlen (trav->name); +                                strncpy (buf + (i - len), trav->name, len); +                                buf[i-len-1] = '/'; +                                i -= (len + 1); +                        } +			*bufp = buf; +                } else { +			gf_log (table->name, GF_LOG_ERROR, +				"out of memory"); +			ret = -ENOMEM; +		} +        } +unlock: +        pthread_mutex_unlock (&table->lock); + +	if (inode->ino == 1 && !name) { +		ret = 1; +		if (buf) { +			FREE (buf); +		} +		buf = CALLOC (ret + 1, sizeof (char)); +		if (buf) { +			strcpy (buf, "/"); +			*bufp = buf; +		} else { +			gf_log (table->name, GF_LOG_ERROR, +				"out of memory"); +			ret = -ENOMEM; +		} +	} + +        return ret; +} + +static int +inode_table_prune (inode_table_t *table) +{ +        int               ret = 0; +        struct list_head  purge = {0, }; +	inode_t          *del = NULL; +	inode_t          *tmp = NULL; +	inode_t          *entry = NULL; + + +        INIT_LIST_HEAD (&purge); + +        pthread_mutex_lock (&table->lock); +        { +                while (table->lru_limit +                       && table->lru_size > (table->lru_limit)) { +         +                        entry = list_entry (table->lru.next, inode_t, list); + +                        table->lru_size--; +                        __inode_retire (entry); + +                        ret++; +                } + +                list_splice_init (&table->purge, &purge); +		table->purge_size = 0; +        } +        pthread_mutex_unlock (&table->lock); + +        { +                list_for_each_entry_safe (del, tmp, &purge, list) { +                        list_del_init (&del->list); +                        __inode_forget (del, 0); +                        __inode_destroy (del); +                } +        } + +        return ret; +} + + +static void +__inode_table_init_root (inode_table_t *table) +{ +        inode_t *root = NULL; +        struct stat stbuf = {0, }; + +        root = __inode_create (table); + +        stbuf.st_ino = 1; +        stbuf.st_mode = S_IFDIR|0755; + +        __inode_link (root, NULL, NULL, &stbuf); +        table->root = root; +} + + +inode_table_t * +inode_table_new (size_t lru_limit, xlator_t *xl) +{ +        inode_table_t *new = NULL; +        int            i = 0; + + +        new = (void *)calloc (1, sizeof (*new)); +        if (!new) +                return NULL; + +        gf_log (xl->name, GF_LOG_DEBUG, +                "creating new inode table with lru_limit=%"GF_PRI_SIZET"", lru_limit); + +        new->xl = xl; + +        new->lru_limit = lru_limit; + +        new->hashsize = 14057; /* TODO: Random Number?? */ + +        new->inode_hash = (void *)calloc (new->hashsize, +                                          sizeof (struct list_head)); +        if (!new->inode_hash) { +                FREE (new); +                return NULL; +        } + +        new->name_hash = (void *)calloc (new->hashsize, +                                         sizeof (struct list_head)); +        if (!new->name_hash) { +                FREE (new->inode_hash); +                FREE (new); +                return NULL; +        } + +        for (i=0; i<new->hashsize; i++) { +                INIT_LIST_HEAD (&new->inode_hash[i]); +        } + + +        for (i=0; i<new->hashsize; i++) { +                INIT_LIST_HEAD (&new->name_hash[i]); +        } + +        INIT_LIST_HEAD (&new->active); +        INIT_LIST_HEAD (&new->lru); +        INIT_LIST_HEAD (&new->purge); + +        asprintf (&new->name, "%s/inode", xl->name); + +	__inode_table_init_root (new); + +        pthread_mutex_init (&new->lock, NULL); + +        return new; +} + + +inode_t * +inode_from_path (inode_table_t *itable, const char *path) +{ +	inode_t  *inode = NULL; +	inode_t  *parent = NULL; +	inode_t  *root = NULL; +	inode_t  *curr = NULL; +	char     *pathname = NULL; +	char     *component = NULL, *next_component = NULL; +	char     *strtokptr = NULL; + +	/* top-down approach */ +	root = itable->root; +	parent = inode_ref (root); +	pathname = strdup (path); +	component = strtok_r (pathname, "/", &strtokptr); + +	if (component == NULL) +		/* root inode */ +		inode = inode_ref (parent); + +	while (component) { +		curr = inode_search (itable, parent->ino, component); +		 +		if (curr == NULL) { +			component = strtok_r (NULL, "/", &strtokptr); +			break; +		} + +		next_component = strtok_r (NULL, "/", &strtokptr); +		 +		if (next_component) { +			inode_unref (parent); +			parent = curr; +			curr = NULL; +		} else { +			inode = curr; +		} +		 +		component = next_component; +	} +	 +	if (parent) +		inode_unref (parent); + +	if (pathname) +		free (pathname); + +	return inode; +} + +int +inode_ctx_put (inode_t *inode, xlator_t *xlator, uint64_t value) +{ +	int index = 0; + +	if (!inode || !xlator) +		return -1; + +	for (index = 0; index < xlator->ctx->xl_count; index++) { +		if (!inode->_ctx[index].key ||  +		    (inode->_ctx[index].key == (uint64_t)(long)xlator)) +			break; +	} +	 +	if (index == xlator->ctx->xl_count) +		return -1; + +	inode->_ctx[index].key   = (uint64_t)(long) xlator; +	inode->_ctx[index].value = value; + +	return 0; +} + +int  +inode_ctx_get (inode_t *inode, xlator_t *xlator, uint64_t *value) +{ +	int index = 0; + +	if (!inode || !xlator) +		return -1; + +	for (index = 0; index < xlator->ctx->xl_count; index++) { +		if (inode->_ctx[index].key == (uint64_t)(long)xlator) +			break; +	} + +	if (index == xlator->ctx->xl_count) +		return -1; + +	if (value)  +		*value = inode->_ctx[index].value; + +	return 0; +} + + +int  +inode_ctx_del (inode_t *inode, xlator_t *xlator, uint64_t *value) +{ +	int index = 0; + +	if (!inode || !xlator) +		return -1; + +	for (index = 0; index < xlator->ctx->xl_count; index++) { +		if (inode->_ctx[index].key == (uint64_t)(long)xlator) +			break; +	} + +	if (index == xlator->ctx->xl_count) +		return -1; + +	if (value)  +		*value = inode->_ctx[index].value;		 + +	inode->_ctx[index].key   = 0; +	inode->_ctx[index].value = 0; + +	return 0; +}  | 
