diff options
| author | Vikas Gorur <vikas@zresearch.com> | 2009-02-18 17:36:07 +0530 | 
|---|---|---|
| committer | Vikas Gorur <vikas@zresearch.com> | 2009-02-18 17:36:07 +0530 | 
| commit | 77adf4cd648dce41f89469dd185deec6b6b53a0b (patch) | |
| tree | 02e155a5753b398ee572b45793f889b538efab6b /libglusterfs/src/fd.c | |
| parent | f3b2e6580e5663292ee113c741343c8a43ee133f (diff) | |
Added all files
Diffstat (limited to 'libglusterfs/src/fd.c')
| -rw-r--r-- | libglusterfs/src/fd.c | 611 | 
1 files changed, 611 insertions, 0 deletions
diff --git a/libglusterfs/src/fd.c b/libglusterfs/src/fd.c new file mode 100644 index 00000000000..78c57884247 --- /dev/null +++ b/libglusterfs/src/fd.c @@ -0,0 +1,611 @@ +/* +  Copyright (c) 2007, 2008, 2009 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/>. +*/ + +#include "fd.h" +#include "glusterfs.h" +#include "inode.h" +#include "dict.h" + + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + + +static uint32_t  +gf_fd_fdtable_expand (fdtable_t *fdtable, uint32_t nr); + +static fd_t * +_fd_ref (fd_t *fd); + +/*  +   Allocate in memory chunks of power of 2 starting from 1024B  +   Assumes fdtable->lock is held +*/ +static inline uint32_t  +gf_roundup_power_of_two (uint32_t nr) +{ +	uint32_t result = nr; + +	if (nr < 0) { +		gf_log ("server-protocol/fd", +			GF_LOG_ERROR, +			"Negative number passed"); +		return -1; +	} + +	switch (nr) { +	case 0: +	case 1:  +		result = 1; +		break; + +	default: +	{ +		uint32_t cnt = 0, tmp = nr; +		uint8_t remainder = 0; +		while (tmp != 1){ +			if (tmp % 2) +				remainder = 1; +			tmp /= 2; +			cnt++; +		} + +		if (remainder) +			result = 0x1 << (cnt + 1); +		break; +	} +	} + +	return result; +} + +static uint32_t  +gf_fd_fdtable_expand (fdtable_t *fdtable, uint32_t nr) +{ +	fd_t **oldfds = NULL; +	uint32_t oldmax_fds = -1; +   +	if (fdtable == NULL || nr < 0) +	{ +		gf_log ("fd", GF_LOG_ERROR, "invalid argument"); +		return EINVAL; +	} +   +	nr /= (1024 / sizeof (fd_t *)); +	nr = gf_roundup_power_of_two (nr + 1); +	nr *= (1024 / sizeof (fd_t *)); + +	oldfds = fdtable->fds; +	oldmax_fds = fdtable->max_fds; + +	fdtable->fds = CALLOC (nr, sizeof (fd_t *)); +	ERR_ABORT (fdtable->fds); +	fdtable->max_fds = nr;  + +	if (oldfds) { +		uint32_t cpy = oldmax_fds * sizeof (fd_t *); +		memcpy (fdtable->fds, oldfds, cpy); +	} + +	FREE (oldfds); +	return 0; +} + +fdtable_t * +gf_fd_fdtable_alloc (void)  +{ +	fdtable_t *fdtable = NULL; + +	fdtable = CALLOC (1, sizeof (*fdtable)); +	if (!fdtable)  +		return NULL; + +	pthread_mutex_init (&fdtable->lock, NULL); + +	pthread_mutex_lock (&fdtable->lock); +	{ +		gf_fd_fdtable_expand (fdtable, 0); +	} +	pthread_mutex_unlock (&fdtable->lock); + +	return fdtable; +} + +void  +gf_fd_fdtable_destroy (fdtable_t *fdtable) +{ +				 +	int32_t i = 0; + +	if (fdtable) { +		pthread_mutex_lock (&fdtable->lock); +		{ +			for (i=0; i < fdtable->max_fds; i++) { +				if (fdtable->fds[i]) { +					fd_t *fd = fdtable->fds[i]; +						   +					fd_unref (fd); +				} +			} + +			FREE (fdtable->fds); +		} +		pthread_mutex_unlock (&fdtable->lock); +		pthread_mutex_destroy (&fdtable->lock); +		FREE (fdtable); +	} +} + +int32_t +gf_fd_unused_get2 (fdtable_t *fdtable, fd_t *fdptr, int32_t fd) +{ +	int32_t ret = -1; +	 +	if (fdtable == NULL || fdptr == NULL || fd < 0) +	{ +		gf_log ("fd", GF_LOG_ERROR, "invalid argument"); +		errno = EINVAL; +		return -1; +	} +  +	pthread_mutex_lock (&fdtable->lock); +	{ +		while (fdtable->max_fds < fd) { +			int error = 0; +			error = gf_fd_fdtable_expand (fdtable, fdtable->max_fds + 1); +			if (error)  +			{ +				gf_log ("fd.c", +					GF_LOG_ERROR, +					"Cannot expand fdtable:%s", strerror (error)); +				goto err; +			} +		} +		 +		if (!fdtable->fds[fd])  +		{ +			fdtable->fds[fd] = fdptr; +			fd_ref (fdptr); +			ret = fd; +		}  +		else  +		{ +			gf_log ("fd.c", +				GF_LOG_ERROR, +				"Cannot allocate fd %d (slot not empty in fdtable)", fd); +		} +	} +err: +	pthread_mutex_unlock (&fdtable->lock); +	 +	return ret; +} + +   +int32_t  +gf_fd_unused_get (fdtable_t *fdtable, fd_t *fdptr) +{ +	int32_t fd = -1, i = 0; +   +	if (fdtable == NULL || fdptr == NULL) +	{ +		gf_log ("fd", GF_LOG_ERROR, "invalid argument"); +		return EINVAL; +	} +   +	pthread_mutex_lock (&fdtable->lock); +	{ +		for (i = 0; i<fdtable->max_fds; i++)  +		{ +			if (!fdtable->fds[i]) +				break; +		} + +		if (i < fdtable->max_fds) { +			fdtable->fds[i] = fdptr; +			fd = i; +		} else { +			int32_t error; +			error = gf_fd_fdtable_expand (fdtable, fdtable->max_fds + 1); +			if (error) { +				gf_log ("server-protocol.c", +					GF_LOG_ERROR, +					"Cannot expand fdtable:%s", strerror (error)); +			} else { +				fdtable->fds[i] = fdptr; +				fd = i; +			} +		} +	} +	pthread_mutex_unlock (&fdtable->lock); + +	return fd; +} + + +inline void  +gf_fd_put (fdtable_t *fdtable, int32_t fd) +{ +	fd_t *fdptr = NULL; +	if (fdtable == NULL || fd < 0) +	{ +		gf_log ("fd", GF_LOG_ERROR, "invalid argument"); +		return; +	} +   +	if (!(fd < fdtable->max_fds)) +	{ +		gf_log ("fd", GF_LOG_ERROR, "invalid argument"); +		return; +	} + +	pthread_mutex_lock (&fdtable->lock); +	{ +		fdptr = fdtable->fds[fd]; +		fdtable->fds[fd] = NULL; +	} +	pthread_mutex_unlock (&fdtable->lock); + +	if (fdptr) { +		fd_unref (fdptr); +	} +} + + +fd_t * +gf_fd_fdptr_get (fdtable_t *fdtable, int64_t fd) +{ +	fd_t *fdptr = NULL; +   +	if (fdtable == NULL || fd < 0) +	{ +		gf_log ("fd", GF_LOG_ERROR, "invalid argument"); +		errno = EINVAL; +		return NULL; +	} +   +	if (!(fd < fdtable->max_fds)) +	{ +		gf_log ("fd", GF_LOG_ERROR, "invalid argument"); +		errno = EINVAL; +		return NULL; +	} + +	pthread_mutex_lock (&fdtable->lock); +	{ +		fdptr = fdtable->fds[fd]; +		if (fdptr) { +			fd_ref (fdptr); +		} +	} +	pthread_mutex_unlock (&fdtable->lock); + +	return fdptr; +} + +fd_t * +_fd_ref (fd_t *fd) +{ +	++fd->refcount; +	 +	return fd; +} + +fd_t * +fd_ref (fd_t *fd) +{ +	fd_t *refed_fd = NULL; + +	if (!fd) { +		gf_log ("fd", GF_LOG_ERROR, "@fd=%p", fd); +		return NULL; +	} + +	LOCK (&fd->inode->lock); +	refed_fd = _fd_ref (fd); +	UNLOCK (&fd->inode->lock); +	 +	return refed_fd; +} + +fd_t * +_fd_unref (fd_t *fd) +{ +	assert (fd->refcount); + +	--fd->refcount; + +	if (fd->refcount == 0){ +		list_del_init (&fd->inode_list); +	} +	 +	return fd; +} + +static void +fd_destroy (fd_t *fd) +{ +        data_pair_t *pair = NULL; +        xlator_t    *xl = NULL; +	int i = 0; + +        if (fd == NULL){ +                gf_log ("xlator", GF_LOG_ERROR, "invalid arugument"); +                goto out; +        } +   +        if (fd->inode == NULL){ +                gf_log ("xlator", GF_LOG_ERROR, "fd->inode is NULL"); +                goto out; +        } +	if (!fd->_ctx) +		goto out; + +        if (S_ISDIR (fd->inode->st_mode)) { +                for (pair = fd->ctx->members_list; pair; pair = pair->next) { +                        /* notify all xlators which have a context */ +                        xl = xlator_search_by_name (fd->inode->table->xl,  +						    pair->key); +           +                        if (!xl) { +                                gf_log ("fd", GF_LOG_CRITICAL, +                                        "fd(%p)->ctx has invalid key(%s)", +                                        fd, pair->key); +                                continue; +                        } +                        if (xl->cbks->releasedir) { +                                xl->cbks->releasedir (xl, fd); +                        } else { +                                gf_log ("fd", GF_LOG_CRITICAL, +                                        "xlator(%s) in fd(%p) no RELEASE cbk", +                                        xl->name, fd); +                        } + +                } +		for (i = 0; i < fd->inode->table->xl->ctx->xl_count; i++) { +			if (fd->_ctx[i].key) { +				xl = (xlator_t *)(long)fd->_ctx[i].key; +				if (xl->cbks->releasedir) +					xl->cbks->releasedir (xl, fd); +			} +		} +        } else { +                for (pair = fd->ctx->members_list; pair; pair = pair->next) { +                        /* notify all xlators which have a context */ +                        xl = xlator_search_by_name (fd->inode->table->xl,  +						    pair->key); +           +                        if (!xl) { +                                gf_log ("fd", GF_LOG_CRITICAL, +                                        "fd(%p)->ctx has invalid key(%s)", +                                        fd, pair->key); +                                continue; +                        } +                        if (xl->cbks->release) { +                                xl->cbks->release (xl, fd); +                        } else { +                                gf_log ("fd", GF_LOG_CRITICAL, +                                        "xlator(%s) in fd(%p) no RELEASE cbk", +                                        xl->name, fd); +                        } +                } +		for (i = 0; i < fd->inode->table->xl->ctx->xl_count; i++) { +			if (fd->_ctx[i].key) { +				xl = (xlator_t *)(long)fd->_ctx[i].key; +				if (xl->cbks->release) +					xl->cbks->release (xl, fd); +			} +		} +        } + +	FREE (fd->_ctx); +        inode_unref (fd->inode); +        fd->inode = (inode_t *)0xaaaaaaaa; +        dict_destroy (fd->ctx); +        FREE (fd); +         +out: +        return; +} + +void +fd_unref (fd_t *fd) +{ +        int32_t refcount = 0; + +        if (!fd) { +                gf_log ("fd.c", GF_LOG_ERROR, "fd is NULL"); +                return; +        } +         +        LOCK (&fd->inode->lock); +        { +                _fd_unref (fd); +                refcount = fd->refcount; +        } +        UNLOCK (&fd->inode->lock); +         +        if (refcount == 0) { +                fd_destroy (fd); +        } + +        return ; +} + +fd_t * +fd_bind (fd_t *fd) +{ +        inode_t *inode = fd->inode; + +        if (!fd) { +                gf_log ("fd.c", GF_LOG_ERROR, "fd is NULL"); +                return NULL; +        } + +        LOCK (&inode->lock); +        { +                list_add (&fd->inode_list, &inode->fd_list); +        } +        UNLOCK (&inode->lock); +         +        return fd; +} + +fd_t * +fd_create (inode_t *inode, pid_t pid) +{ +        fd_t *fd = NULL; +   +        if (inode == NULL) { +                gf_log ("fd", GF_LOG_ERROR, "invalid argument"); +                return NULL; +        } +   +        fd = CALLOC (1, sizeof (fd_t)); +        ERR_ABORT (fd); +   +	fd->_ctx = CALLOC (1, (sizeof (struct _fd_ctx) *  +			       inode->table->xl->ctx->xl_count)); +        fd->ctx = get_new_dict (); +        fd->inode = inode_ref (inode); +        fd->pid = pid; +        INIT_LIST_HEAD (&fd->inode_list); +         +        LOCK (&inode->lock); +        fd = _fd_ref (fd); +        UNLOCK (&inode->lock); + +        return fd; +} + +fd_t * +fd_lookup (inode_t *inode, pid_t pid) +{ +        fd_t *fd = NULL; +        fd_t *iter_fd = NULL; + +        LOCK (&inode->lock); +        { +                if (list_empty (&inode->fd_list)) { +                        fd = NULL; +                } else { +                        list_for_each_entry (iter_fd, &inode->fd_list, inode_list) { +                                if (pid) { +                                        if (iter_fd->pid == pid) { +                                                fd = _fd_ref (iter_fd); +                                                break; +                                        } +                                } else { +                                        fd = _fd_ref (iter_fd); +                                        break; +                                } +                        } +                } +        } +        UNLOCK (&inode->lock); +         +        return fd; +} + +uint8_t +fd_list_empty (inode_t *inode) +{ +        uint8_t empty = 0;  + +        LOCK (&inode->lock); +        { +                empty = list_empty (&inode->fd_list); +        } +        UNLOCK (&inode->lock); +         +        return empty; +} + +int +fd_ctx_set (fd_t *fd, xlator_t *xlator, uint64_t value) +{ +	int index = 0; + +	if (!fd || !xlator) +		return -1; + +	for (index = 0; index < xlator->ctx->xl_count; index++) { +		if (!fd->_ctx[index].key ||  +		    (fd->_ctx[index].key == (uint64_t)(long)xlator)) +			break; +	} +	 +	if (index == xlator->ctx->xl_count) +		return -1; + +	fd->_ctx[index].key   = (uint64_t)(long) xlator; +	fd->_ctx[index].value = value; + +	return 0; +} + +int  +fd_ctx_get (fd_t *fd, xlator_t *xlator, uint64_t *value) +{ +	int index = 0; + +	if (!fd || !xlator) +		return -1; + +	for (index = 0; index < xlator->ctx->xl_count; index++) { +		if (fd->_ctx[index].key == (uint64_t)(long)xlator) +			break; +	} + +	if (index == xlator->ctx->xl_count) +		return -1; + +	if (value)  +		*value = fd->_ctx[index].value; + +	return 0; +} + + +int  +fd_ctx_del (fd_t *fd, xlator_t *xlator, uint64_t *value) +{ +	int index = 0; + +	if (!fd || !xlator) +		return -1; + +	for (index = 0; index < xlator->ctx->xl_count; index++) { +		if (fd->_ctx[index].key == (uint64_t)(long)xlator) +			break; +	} + +	if (index == xlator->ctx->xl_count) +		return -1; + +	if (value)  +		*value = fd->_ctx[index].value;		 + +	fd->_ctx[index].key   = 0; +	fd->_ctx[index].value = 0; + +	return 0; +}  | 
