665 lines · 15.8 KB · C
RawDownload
/* * drivers/misc/logger.c * * A Logging Subsystem * * Copyright (C) 2007-2008 Google, Inc. * * Robert Love <rlove@google.com> * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program 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. */ #include <linux/sched.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/miscdevice.h>#include <linux/uaccess.h>#include <linux/poll.h>#include <linux/slab.h>#include <linux/time.h>#include <linux/vmalloc.h>#include "logger.h" #include <asm/ioctls.h> /* * struct logger_log - represents a specific log, such as 'main' or 'radio' * * This structure lives from module insertion until module removal, so it does * not need additional reference counting. The structure is protected by the * mutex 'mutex'. */struct logger_log {	unsigned char		*buffer;/* the ring buffer itself */	struct miscdevice	misc;	/* misc device representing the log */	wait_queue_head_t	wq;	/* wait queue for readers */	struct list_head	readers; /* this log's readers */	struct mutex		mutex;	/* mutex protecting buffer */	size_t			w_off;	/* current write head offset */	size_t			head;	/* new readers start here */	size_t			size;	/* size of the log */	struct list_head	logs;	/* list of log channels (myself)*/}; static LIST_HEAD(log_list);  /* * struct logger_reader - a logging device open for reading * * This object lives from open to release, so we don't need additional * reference counting. The structure is protected by log->mutex. */struct logger_reader {	struct logger_log	*log;	/* associated log */	struct list_head	list;	/* entry in logger_log's list */	size_t			r_off;	/* current read head offset */}; /* logger_offset - returns index 'n' into the log via (optimized) modulus */static size_t logger_offset(struct logger_log *log, size_t n){	return n & (log->size - 1);}  /* * file_get_log - Given a file structure, return the associated log * * This isn't aesthetic. We have several goals: * *	1) Need to quickly obtain the associated log during an I/O operation *	2) Readers need to maintain state (logger_reader) *	3) Writers need to be very fast (open() should be a near no-op) * * In the reader case, we can trivially go file->logger_reader->logger_log. * For a writer, we don't want to maintain a logger_reader, so we just go * file->logger_log. Thus what file->private_data points at depends on whether * or not the file was opened for reading. This function hides that dirtiness. */static inline struct logger_log *file_get_log(struct file *file){	if (file->f_mode & FMODE_READ) {		struct logger_reader *reader = file->private_data;		return reader->log;	} else		return file->private_data;} /* * get_entry_len - Grabs the length of the payload of the next entry starting * from 'off'. * * An entry length is 2 bytes (16 bits) in host endian order. * In the log, the length does not include the size of the log entry structure. * This function returns the size including the log entry structure. * * Caller needs to hold log->mutex. */static __u32 get_entry_len(struct logger_log *log, size_t off){	__u16 val; 	/* copy 2 bytes from buffer, in memcpy order, */	/* handling possible wrap at end of buffer */ 	((__u8 *)&val)[0] = log->buffer[off];	if (likely(off+1 < log->size))		((__u8 *)&val)[1] = log->buffer[off+1];	else		((__u8 *)&val)[1] = log->buffer[0]; 	return sizeof(struct logger_entry) + val;} /* * do_read_log_to_user - reads exactly 'count' bytes from 'log' into the * user-space buffer 'buf'. Returns 'count' on success. * * Caller must hold log->mutex. */static ssize_t do_read_log_to_user(struct logger_log *log,				   struct logger_reader *reader,				   char __user *buf,				   size_t count){	size_t len; 	/*	 * We read from the log in two disjoint operations. First, we read from	 * the current read head offset up to 'count' bytes or to the end of	 * the log, whichever comes first.	 */	len = min(count, log->size - reader->r_off);	if (copy_to_user(buf, log->buffer + reader->r_off, len))		return -EFAULT; 	/*	 * Second, we read any remaining bytes, starting back at the head of	 * the log.	 */	if (count != len)		if (copy_to_user(buf + len, log->buffer, count - len))			return -EFAULT; 	reader->r_off = logger_offset(log, reader->r_off + count); 	return count;} /* * logger_read - our log's read() method * * Behavior: * *	- O_NONBLOCK works *	- If there are no log entries to read, blocks until log is written to *	- Atomically reads exactly one log entry * * Optimal read size is LOGGER_ENTRY_MAX_LEN. Will set errno to EINVAL if read * buffer is insufficient to hold next entry. */static ssize_t logger_read(struct file *file, char __user *buf,			   size_t count, loff_t *pos){	struct logger_reader *reader = file->private_data;	struct logger_log *log = reader->log;	ssize_t ret;	DEFINE_WAIT(wait); start:	while (1) {		mutex_lock(&log->mutex); 		prepare_to_wait(&log->wq, &wait, TASK_INTERRUPTIBLE); 		ret = (log->w_off == reader->r_off);		mutex_unlock(&log->mutex);		if (!ret)			break; 		if (file->f_flags & O_NONBLOCK) {			ret = -EAGAIN;			break;		} 		if (signal_pending(current)) {			ret = -EINTR;			break;		} 		schedule();	} 	finish_wait(&log->wq, &wait);	if (ret)		return ret; 	mutex_lock(&log->mutex); 	/* is there still something to read or did we race? */	if (unlikely(log->w_off == reader->r_off)) {		mutex_unlock(&log->mutex);		goto start;	} 	/* get the size of the next entry */	ret = get_entry_len(log, reader->r_off);	if (count < ret) {		ret = -EINVAL;		goto out;	} 	/* get exactly one entry from the log */	ret = do_read_log_to_user(log, reader, buf, ret); out:	mutex_unlock(&log->mutex); 	return ret;} /* * get_next_entry - return the offset of the first valid entry at least 'len' * bytes after 'off'. * * Caller must hold log->mutex. */static size_t get_next_entry(struct logger_log *log, size_t off, size_t len){	size_t count = 0; 	do {		size_t nr = get_entry_len(log, off);		off = logger_offset(log, off + nr);		count += nr;	} while (count < len); 	return off;} /* * is_between - is a < c < b, accounting for wrapping of a, b, and c *    positions in the buffer * * That is, if a<b, check for c between a and b * and if a>b, check for c outside (not between) a and b * * |------- a xxxxxxxx b --------| *               c^ * * |xxxxx b --------- a xxxxxxxxx| *    c^ *  or                    c^ */static inline int is_between(size_t a, size_t b, size_t c){	if (a < b) {		/* is c between a and b? */		if (a < c && c <= b)			return 1;	} else {		/* is c outside of b through a? */		if (c <= b || a < c)			return 1;	} 	return 0;} /* * fix_up_readers - walk the list of all readers and "fix up" any who were * lapped by the writer; also do the same for the default "start head". * We do this by "pulling forward" the readers and start head to the first * entry after the new write head. * * The caller needs to hold log->mutex. */static void fix_up_readers(struct logger_log *log, size_t len){	size_t old = log->w_off;	size_t new = logger_offset(log, old + len);	struct logger_reader *reader; 	if (is_between(old, new, log->head))		log->head = get_next_entry(log, log->head, len); 	list_for_each_entry(reader, &log->readers, list)		if (is_between(old, new, reader->r_off))			reader->r_off = get_next_entry(log, reader->r_off, len);} /* * do_write_log - writes 'len' bytes from 'buf' to 'log' * * The caller needs to hold log->mutex. */static void do_write_log(struct logger_log *log, const void *buf, size_t count){	size_t len; 	len = min(count, log->size - log->w_off);	memcpy(log->buffer + log->w_off, buf, len); 	if (count != len)		memcpy(log->buffer, buf + len, count - len); 	log->w_off = logger_offset(log, log->w_off + count); } /* * do_write_log_user - writes 'len' bytes from the user-space buffer 'buf' to * the log 'log' * * The caller needs to hold log->mutex. * * Returns 'count' on success, negative error code on failure. */static ssize_t do_write_log_from_user(struct logger_log *log,				      const void __user *buf, size_t count){	size_t len; 	len = min(count, log->size - log->w_off);	if (len && copy_from_user(log->buffer + log->w_off, buf, len))		return -EFAULT; 	if (count != len)		if (copy_from_user(log->buffer, buf + len, count - len))			/*			 * Note that by not updating w_off, this abandons the			 * portion of the new entry that *was* successfully			 * copied, just above.  This is intentional to avoid			 * message corruption from missing fragments.			 */			return -EFAULT; 	log->w_off = logger_offset(log, log->w_off + count); 	return count;} /* * logger_aio_write - our write method, implementing support for write(), * writev(), and aio_write(). Writes are our fast path, and we try to optimize * them above all else. */static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,			 unsigned long nr_segs, loff_t ppos){	struct logger_log *log = file_get_log(iocb->ki_filp);	size_t orig = log->w_off;	struct logger_entry header;	struct timespec now;	ssize_t ret = 0; 	now = current_kernel_time(); 	header.pid = current->tgid;	header.tid = current->pid;	header.sec = now.tv_sec;	header.nsec = now.tv_nsec;	header.len = min_t(size_t, iocb->ki_left, LOGGER_ENTRY_MAX_PAYLOAD); 	/* null writes succeed, return zero */	if (unlikely(!header.len))		return 0; 	mutex_lock(&log->mutex); 	/*	 * Fix up any readers, pulling them forward to the first readable	 * entry after (what will be) the new write offset. We do this now	 * because if we partially fail, we can end up with clobbered log	 * entries that encroach on readable buffer.	 */	fix_up_readers(log, sizeof(struct logger_entry) + header.len); 	do_write_log(log, &header, sizeof(struct logger_entry)); 	while (nr_segs-- > 0) {		size_t len;		ssize_t nr; 		/* figure out how much of this vector we can keep */		len = min_t(size_t, iov->iov_len, header.len - ret); 		/* write out this segment's payload */		nr = do_write_log_from_user(log, iov->iov_base, len);		if (unlikely(nr < 0)) {			log->w_off = orig;			mutex_unlock(&log->mutex);			return nr;		} 		iov++;		ret += nr;	} 	mutex_unlock(&log->mutex); 	/* wake up any blocked readers */	wake_up_interruptible(&log->wq); 	return ret;} static struct logger_log *get_log_from_minor(int minor){	struct logger_log *log; 	list_for_each_entry(log, &log_list, logs)		if (log->misc.minor == minor)			return log;	return NULL;} /* * logger_open - the log's open() file operation * * Note how near a no-op this is in the write-only case. Keep it that way! */static int logger_open(struct inode *inode, struct file *file){	struct logger_log *log;	int ret; 	ret = nonseekable_open(inode, file);	if (ret)		return ret; 	log = get_log_from_minor(MINOR(inode->i_rdev));	if (!log)		return -ENODEV; 	if (file->f_mode & FMODE_READ) {		struct logger_reader *reader; 		reader = kmalloc(sizeof(struct logger_reader), GFP_KERNEL);		if (!reader)			return -ENOMEM; 		reader->log = log;		INIT_LIST_HEAD(&reader->list); 		mutex_lock(&log->mutex);		reader->r_off = log->head;		list_add_tail(&reader->list, &log->readers);		mutex_unlock(&log->mutex); 		file->private_data = reader;	} else		file->private_data = log; 	return 0;} /* * logger_release - the log's release file operation * * Note this is a total no-op in the write-only case. Keep it that way! */static int logger_release(struct inode *ignored, struct file *file){	if (file->f_mode & FMODE_READ) {		struct logger_reader *reader = file->private_data;		struct logger_log *log = reader->log; 		mutex_lock(&log->mutex);		list_del(&reader->list);		mutex_unlock(&log->mutex); 		kfree(reader);	} 	return 0;} /* * logger_poll - the log's poll file operation, for poll/select/epoll * * Note we always return POLLOUT, because you can always write() to the log. * Note also that, strictly speaking, a return value of POLLIN does not * guarantee that the log is readable without blocking, as there is a small * chance that the writer can lap the reader in the interim between poll() * returning and the read() request. */static unsigned int logger_poll(struct file *file, poll_table *wait){	struct logger_reader *reader;	struct logger_log *log;	unsigned int ret = POLLOUT | POLLWRNORM;

Lines 1–500 of 665.