⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ulockmgr.c

📁 FUSE文件系统开发工具,将内核层面的文件系统开发过程平移到应用层面上来。
💻 C
字号:
/*  libulockmgr: Userspace Lock Manager Library  Copyright (C) 2006  Miklos Szeredi <miklos@szeredi.hu>  This program can be distributed under the terms of the GNU LGPLv2.  See the file COPYING.LIB*//* #define DEBUG 1 */#include "ulockmgr.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <errno.h>#include <assert.h>#include <signal.h>#include <sys/stat.h>#include <sys/socket.h>#include <sys/wait.h>struct message {	unsigned intr : 1;	unsigned nofd : 1;	pthread_t thr;	int cmd;	int fd;	struct flock lock;	int error;};struct fd_store {	struct fd_store *next;	int fd;	int inuse;};struct owner {	struct owner *next;	struct owner *prev;	struct fd_store *fds;	void *id;	size_t id_len;	int cfd;};static pthread_mutex_t ulockmgr_lock;static int ulockmgr_cfd = -1;static struct owner owner_list = { .next = &owner_list, .prev = &owner_list };#define MAX_SEND_FDS 2static void list_del_owner(struct owner *owner){	struct owner *prev = owner->prev;	struct owner *next = owner->next;	prev->next = next;	next->prev = prev;}static void list_add_owner(struct owner *owner, struct owner *next){	struct owner *prev = next->prev;	owner->next = next;	owner->prev = prev;	prev->next = owner;	next->prev = owner;}/* * There's a bug in the linux kernel (< 2.6.22) recv() implementation * on AF_UNIX, SOCK_STREAM sockets, that could cause it to return * zero, even if data was available.  Retrying the recv will return * the data in this case. */static int do_recv(int sock, void *buf, size_t len, int flags){	int res = recv(sock, buf, len, flags);	if (res == 0)		res = recv(sock, buf, len, flags);	return res;}static int ulockmgr_send_message(int sock, void *buf, size_t buflen,				 int *fdp, int numfds){	struct msghdr msg;	struct cmsghdr *p_cmsg;	struct iovec vec;	size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)];	int res;	assert(numfds <= MAX_SEND_FDS);	msg.msg_control = cmsgbuf;	msg.msg_controllen = sizeof(cmsgbuf);	p_cmsg = CMSG_FIRSTHDR(&msg);	p_cmsg->cmsg_level = SOL_SOCKET;	p_cmsg->cmsg_type = SCM_RIGHTS;	p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds);	memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds);	msg.msg_controllen = p_cmsg->cmsg_len;	msg.msg_name = NULL;	msg.msg_namelen = 0;	msg.msg_iov = &vec;	msg.msg_iovlen = 1;	msg.msg_flags = 0;	vec.iov_base = buf;	vec.iov_len = buflen;	res = sendmsg(sock, &msg, MSG_NOSIGNAL);	if (res == -1) {		perror("libulockmgr: sendmsg");		return -1;	}	if ((size_t) res != buflen) {		fprintf(stderr, "libulockmgr: sendmsg short\n");		return -1;	}	return 0;}static int ulockmgr_start_daemon(void){	int sv[2];	int res;	char tmp[64];	res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);	if (res == -1) {		perror("libulockmgr: socketpair");		return -1;	}	snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]);	res = system(tmp);	close(sv[0]);	if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) {		close(sv[1]);		return -1;	}	ulockmgr_cfd = sv[1];	return 0;}static struct owner *ulockmgr_new_owner(const void *id, size_t id_len){	int sv[2];	int res;	char c = 'm';	struct owner *o;	if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1)		return NULL;	o = calloc(1, sizeof(struct owner) + id_len);	if (!o) {		fprintf(stderr, "libulockmgr: failed to allocate memory\n");		return NULL;	}	o->id = o + 1;	o->id_len = id_len;	res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);	if (res == -1) {		perror("libulockmgr: socketpair");		goto out_free;	}	res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1);	close(sv[0]);	if (res == -1) {		close(ulockmgr_cfd);		ulockmgr_cfd = -1;		goto out_close;	}	o->cfd = sv[1];	memcpy(o->id, id, id_len);	list_add_owner(o, &owner_list);	return o;out_close:	close(sv[1]);out_free:	free(o);	return NULL;}static int ulockmgr_send_request(struct message *msg, const void *id,				 size_t id_len){	int sv[2];	int cfd;	struct owner *o;	struct fd_store *f = NULL;	struct fd_store *newf = NULL;	struct fd_store **fp;	int fd = msg->fd;	int cmd = msg->cmd;	int res;	int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK &&			 msg->lock.l_start == 0 && msg->lock.l_len == 0);	for (o = owner_list.next; o != &owner_list; o = o->next)		if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0)			break;	if (o == &owner_list)		o = NULL;	if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK)		o = ulockmgr_new_owner(id, id_len);	if (!o) {		if (cmd == F_GETLK) {			res = fcntl(msg->fd, F_GETLK, &msg->lock);			return (res == -1) ? -errno : 0;		} else if (msg->lock.l_type == F_UNLCK)			return 0;		else			return -ENOLCK;	}	if (unlockall)		msg->nofd = 1;	else {		for (fp = &o->fds; *fp; fp = &(*fp)->next) {			f = *fp;			if (f->fd == fd) {				msg->nofd = 1;				break;			}		}	}	if (!msg->nofd) {		newf = f = calloc(1, sizeof(struct fd_store));		if (!f) {			fprintf(stderr, "libulockmgr: failed to allocate memory\n");			return -ENOLCK;		}	}	res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);	if (res == -1) {		perror("libulockmgr: socketpair");		free(newf);		return -ENOLCK;	}	cfd = sv[1];	sv[1] = msg->fd;	res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv,				    msg->nofd ? 1 : 2);	close(sv[0]);	if (res == -1) {		free(newf);		close(cfd);		return -EIO;	}	if (newf) {		newf->fd = msg->fd;		newf->next = o->fds;		o->fds = newf;	}	if (f)		f->inuse++;	res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL);	if (res == -1) {		perror("libulockmgr: recv");		msg->error = EIO;	} else if (res != sizeof(struct message)) {		fprintf(stderr, "libulockmgr: recv short\n");		msg->error = EIO;	} else if (cmd == F_SETLKW && msg->error == EAGAIN) {		pthread_mutex_unlock(&ulockmgr_lock);		while (1) {			sigset_t old;			sigset_t unblock;			int errno_save;			sigemptyset(&unblock);			sigaddset(&unblock, SIGUSR1);			pthread_sigmask(SIG_UNBLOCK, &unblock, &old);			res = do_recv(cfd, msg, sizeof(struct message),				      MSG_WAITALL);			errno_save = errno;			pthread_sigmask(SIG_SETMASK, &old, NULL);			if (res == sizeof(struct message))				break;			else if (res >= 0) {				fprintf(stderr, "libulockmgr: recv short\n");				msg->error = EIO;				break;			} else if (errno_save != EINTR) {				errno = errno_save;				perror("libulockmgr: recv");				msg->error = EIO;				break;			}			msg->intr = 1;			res = send(o->cfd, msg, sizeof(struct message),				   MSG_NOSIGNAL);			if (res == -1) {				perror("libulockmgr: send");				msg->error = EIO;				break;			}			if (res != sizeof(struct message)) {				fprintf(stderr, "libulockmgr: send short\n");				msg->error = EIO;				break;			}		}		pthread_mutex_lock(&ulockmgr_lock);	}	if (f)		f->inuse--;	close(cfd);	if (unlockall) {		for (fp = &o->fds; *fp;) {			f = *fp;			if (f->fd == fd && !f->inuse) {				*fp = f->next;				free(f);			} else				fp = &f->next;		}		if (!o->fds) {			list_del_owner(o);			close(o->cfd);			free(o);		}		/* Force OK on unlock-all, since it _will_ succeed once the		   owner is deleted */		msg->error = 0;	}	return -msg->error;}#ifdef DEBUGstatic uint32_t owner_hash(const unsigned char *id, size_t id_len){	uint32_t h = 0;	size_t i;	for (i = 0; i < id_len; i++)		h = ((h << 8) | (h >> 24)) ^ id[i];	return h;}#endifstatic int ulockmgr_canonicalize(int fd, struct flock *lock){	off_t offset;	if (lock->l_whence == SEEK_CUR) {		offset = lseek(fd, 0, SEEK_CUR);		if (offset == (off_t) -1)			return -errno;	} else if (lock->l_whence == SEEK_END) {		struct stat stbuf;		int res = fstat(fd, &stbuf);		if (res == -1)			return -errno;		offset = stbuf.st_size;	} else		offset = 0;	lock->l_whence = SEEK_SET;	lock->l_start += offset;	if (lock->l_start < 0)		return -EINVAL;	if (lock->l_len < 0) {		lock->l_start += lock->l_len;		if (lock->l_start < 0)			return -EINVAL;		lock->l_len = -lock->l_len;	}	if (lock->l_len && lock->l_start + lock->l_len - 1 < 0)		return -EINVAL;	return 0;}int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner,		size_t owner_len){	int err;	struct message msg;	sigset_t old;	sigset_t block;	if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW)		return -EINVAL;	if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR &&	    lock->l_whence != SEEK_END)		return -EINVAL;#ifdef DEBUG	fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n",		cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len,		owner_hash(owner, owner_len));#endif	/* Unlock should never block anyway */	if (cmd == F_SETLKW && lock->l_type == F_UNLCK)		cmd = F_SETLK;	memset(&msg, 0, sizeof(struct message));	msg.cmd = cmd;	msg.fd = fd;	msg.lock = *lock;	err = ulockmgr_canonicalize(fd, &msg.lock);	if (err)		return err;	sigemptyset(&block);	sigaddset(&block, SIGUSR1);	pthread_sigmask(SIG_BLOCK, &block, &old);	pthread_mutex_lock(&ulockmgr_lock);	err = ulockmgr_send_request(&msg, owner, owner_len);	pthread_mutex_unlock(&ulockmgr_lock);	pthread_sigmask(SIG_SETMASK, &old, NULL);	if (!err && cmd == F_GETLK) {		if (msg.lock.l_type == F_UNLCK)			lock->l_type = F_UNLCK;		else			*lock = msg.lock;	}	return err;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -