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

📄 relay.c

📁 Kernel code of linux kernel
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (chan->has_base_filename) {		dentry = relay_create_buf_file(chan, buf, cpu);		if (!dentry)			goto free_buf;		relay_set_buf_dentry(buf, dentry);	} 	buf->cpu = cpu; 	__relay_reset(buf, 1); 	if(chan->is_global) { 		chan->buf[0] = buf; 		buf->cpu = 0;  	}	return buf;free_buf: 	relay_destroy_buf(buf);	return NULL;}/** *	relay_close_buf - close a channel buffer *	@buf: channel buffer * *	Marks the buffer finalized and restores the default callbacks. *	The channel buffer and channel buffer data structure are then freed *	automatically when the last reference is given up. */static void relay_close_buf(struct rchan_buf *buf){	buf->finalized = 1;	del_timer_sync(&buf->timer);	kref_put(&buf->kref, relay_remove_buf);}static void setup_callbacks(struct rchan *chan,				   struct rchan_callbacks *cb){	if (!cb) {		chan->cb = &default_channel_callbacks;		return;	}	if (!cb->subbuf_start)		cb->subbuf_start = subbuf_start_default_callback;	if (!cb->buf_mapped)		cb->buf_mapped = buf_mapped_default_callback;	if (!cb->buf_unmapped)		cb->buf_unmapped = buf_unmapped_default_callback;	if (!cb->create_buf_file)		cb->create_buf_file = create_buf_file_default_callback;	if (!cb->remove_buf_file)		cb->remove_buf_file = remove_buf_file_default_callback;	chan->cb = cb;}/** * 	relay_hotcpu_callback - CPU hotplug callback * 	@nb: notifier block * 	@action: hotplug action to take * 	@hcpu: CPU number * * 	Returns the success/failure of the operation. (%NOTIFY_OK, %NOTIFY_BAD) */static int __cpuinit relay_hotcpu_callback(struct notifier_block *nb,				unsigned long action,				void *hcpu){	unsigned int hotcpu = (unsigned long)hcpu;	struct rchan *chan;	switch(action) {	case CPU_UP_PREPARE:	case CPU_UP_PREPARE_FROZEN:		mutex_lock(&relay_channels_mutex);		list_for_each_entry(chan, &relay_channels, list) {			if (chan->buf[hotcpu])				continue;			chan->buf[hotcpu] = relay_open_buf(chan, hotcpu);			if(!chan->buf[hotcpu]) {				printk(KERN_ERR					"relay_hotcpu_callback: cpu %d buffer "					"creation failed\n", hotcpu);				mutex_unlock(&relay_channels_mutex);				return NOTIFY_BAD;			}		}		mutex_unlock(&relay_channels_mutex);		break;	case CPU_DEAD:	case CPU_DEAD_FROZEN:		/* No need to flush the cpu : will be flushed upon		 * final relay_flush() call. */		break;	}	return NOTIFY_OK;}/** *	relay_open - create a new relay channel *	@base_filename: base name of files to create, %NULL for buffering only *	@parent: dentry of parent directory, %NULL for root directory or buffer *	@subbuf_size: size of sub-buffers *	@n_subbufs: number of sub-buffers *	@cb: client callback functions *	@private_data: user-defined data * *	Returns channel pointer if successful, %NULL otherwise. * *	Creates a channel buffer for each cpu using the sizes and *	attributes specified.  The created channel buffer files *	will be named base_filename0...base_filenameN-1.  File *	permissions will be %S_IRUSR. */struct rchan *relay_open(const char *base_filename,			 struct dentry *parent,			 size_t subbuf_size,			 size_t n_subbufs,			 struct rchan_callbacks *cb,			 void *private_data){	unsigned int i;	struct rchan *chan;	if (!(subbuf_size && n_subbufs))		return NULL;	chan = kzalloc(sizeof(struct rchan), GFP_KERNEL);	if (!chan)		return NULL;	chan->version = RELAYFS_CHANNEL_VERSION;	chan->n_subbufs = n_subbufs;	chan->subbuf_size = subbuf_size;	chan->alloc_size = FIX_SIZE(subbuf_size * n_subbufs);	chan->parent = parent;	chan->private_data = private_data;	if (base_filename) {		chan->has_base_filename = 1;		strlcpy(chan->base_filename, base_filename, NAME_MAX);	}	setup_callbacks(chan, cb);	kref_init(&chan->kref);	mutex_lock(&relay_channels_mutex);	for_each_online_cpu(i) {		chan->buf[i] = relay_open_buf(chan, i);		if (!chan->buf[i])			goto free_bufs;	}	list_add(&chan->list, &relay_channels);	mutex_unlock(&relay_channels_mutex);	return chan;free_bufs:	for_each_online_cpu(i) {		if (!chan->buf[i])			break;		relay_close_buf(chan->buf[i]);	}	kref_put(&chan->kref, relay_destroy_channel);	mutex_unlock(&relay_channels_mutex);	return NULL;}EXPORT_SYMBOL_GPL(relay_open);struct rchan_percpu_buf_dispatcher {	struct rchan_buf *buf;	struct dentry *dentry;};/* Called in atomic context. */static void __relay_set_buf_dentry(void *info){	struct rchan_percpu_buf_dispatcher *p = info;	relay_set_buf_dentry(p->buf, p->dentry);}/** *	relay_late_setup_files - triggers file creation *	@chan: channel to operate on *	@base_filename: base name of files to create *	@parent: dentry of parent directory, %NULL for root directory * *	Returns 0 if successful, non-zero otherwise. * *	Use to setup files for a previously buffer-only channel. *	Useful to do early tracing in kernel, before VFS is up, for example. */int relay_late_setup_files(struct rchan *chan,			   const char *base_filename,			   struct dentry *parent){	int err = 0;	unsigned int i, curr_cpu;	unsigned long flags;	struct dentry *dentry;	struct rchan_percpu_buf_dispatcher disp;	if (!chan || !base_filename)		return -EINVAL;	strlcpy(chan->base_filename, base_filename, NAME_MAX);	mutex_lock(&relay_channels_mutex);	/* Is chan already set up? */	if (unlikely(chan->has_base_filename))		return -EEXIST;	chan->has_base_filename = 1;	chan->parent = parent;	curr_cpu = get_cpu();	/*	 * The CPU hotplug notifier ran before us and created buffers with	 * no files associated. So it's safe to call relay_setup_buf_file()	 * on all currently online CPUs.	 */	for_each_online_cpu(i) {		if (unlikely(!chan->buf[i])) {			printk(KERN_ERR "relay_late_setup_files: CPU %u "					"has no buffer, it must have!\n", i);			BUG();			err = -EINVAL;			break;		}		dentry = relay_create_buf_file(chan, chan->buf[i], i);		if (unlikely(!dentry)) {			err = -EINVAL;			break;		}		if (curr_cpu == i) {			local_irq_save(flags);			relay_set_buf_dentry(chan->buf[i], dentry);			local_irq_restore(flags);		} else {			disp.buf = chan->buf[i];			disp.dentry = dentry;			smp_mb();			/* relay_channels_mutex must be held, so wait. */			err = smp_call_function_single(i,						       __relay_set_buf_dentry,						       &disp, 1);		}		if (unlikely(err))			break;	}	put_cpu();	mutex_unlock(&relay_channels_mutex);	return err;}/** *	relay_switch_subbuf - switch to a new sub-buffer *	@buf: channel buffer *	@length: size of current event * *	Returns either the length passed in or 0 if full. * *	Performs sub-buffer-switch tasks such as invoking callbacks, *	updating padding counts, waking up readers, etc. */size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length){	void *old, *new;	size_t old_subbuf, new_subbuf;	if (unlikely(length > buf->chan->subbuf_size))		goto toobig;	if (buf->offset != buf->chan->subbuf_size + 1) {		buf->prev_padding = buf->chan->subbuf_size - buf->offset;		old_subbuf = buf->subbufs_produced % buf->chan->n_subbufs;		buf->padding[old_subbuf] = buf->prev_padding;		buf->subbufs_produced++;		if (buf->dentry)			buf->dentry->d_inode->i_size +=				buf->chan->subbuf_size -				buf->padding[old_subbuf];		else			buf->early_bytes += buf->chan->subbuf_size -					    buf->padding[old_subbuf];		smp_mb();		if (waitqueue_active(&buf->read_wait))			/*			 * Calling wake_up_interruptible() from here			 * will deadlock if we happen to be logging			 * from the scheduler (trying to re-grab			 * rq->lock), so defer it.			 */			__mod_timer(&buf->timer, jiffies + 1);	}	old = buf->data;	new_subbuf = buf->subbufs_produced % buf->chan->n_subbufs;	new = buf->start + new_subbuf * buf->chan->subbuf_size;	buf->offset = 0;	if (!buf->chan->cb->subbuf_start(buf, new, old, buf->prev_padding)) {		buf->offset = buf->chan->subbuf_size + 1;		return 0;	}	buf->data = new;	buf->padding[new_subbuf] = 0;	if (unlikely(length + buf->offset > buf->chan->subbuf_size))		goto toobig;	return length;toobig:	buf->chan->last_toobig = length;	return 0;}EXPORT_SYMBOL_GPL(relay_switch_subbuf);/** *	relay_subbufs_consumed - update the buffer's sub-buffers-consumed count *	@chan: the channel *	@cpu: the cpu associated with the channel buffer to update *	@subbufs_consumed: number of sub-buffers to add to current buf's count * *	Adds to the channel buffer's consumed sub-buffer count. *	subbufs_consumed should be the number of sub-buffers newly consumed, *	not the total consumed. * *	NOTE. Kernel clients don't need to call this function if the channel *	mode is 'overwrite'. */void relay_subbufs_consumed(struct rchan *chan,			    unsigned int cpu,			    size_t subbufs_consumed){	struct rchan_buf *buf;	if (!chan)		return;	if (cpu >= NR_CPUS || !chan->buf[cpu])		return;	buf = chan->buf[cpu];	buf->subbufs_consumed += subbufs_consumed;	if (buf->subbufs_consumed > buf->subbufs_produced)		buf->subbufs_consumed = buf->subbufs_produced;}EXPORT_SYMBOL_GPL(relay_subbufs_consumed);/** *	relay_close - close the channel *	@chan: the channel * *	Closes all channel buffers and frees the channel. */void relay_close(struct rchan *chan){	unsigned int i;	if (!chan)		return;	mutex_lock(&relay_channels_mutex);	if (chan->is_global && chan->buf[0])		relay_close_buf(chan->buf[0]);	else		for_each_possible_cpu(i)			if (chan->buf[i])				relay_close_buf(chan->buf[i]);	if (chan->last_toobig)		printk(KERN_WARNING "relay: one or more items not logged "		       "[item size (%Zd) > sub-buffer size (%Zd)]\n",		       chan->last_toobig, chan->subbuf_size);	list_del(&chan->list);	kref_put(&chan->kref, relay_destroy_channel);	mutex_unlock(&relay_channels_mutex);}EXPORT_SYMBOL_GPL(relay_close);/** *	relay_flush - close the channel *	@chan: the channel * *	Flushes all channel buffers, i.e. forces buffer switch. */void relay_flush(struct rchan *chan){	unsigned int i;	if (!chan)		return;	if (chan->is_global && chan->buf[0]) {		relay_switch_subbuf(chan->buf[0], 0);		return;	}	mutex_lock(&relay_channels_mutex);	for_each_possible_cpu(i)		if (chan->buf[i])			relay_switch_subbuf(chan->buf[i], 0);	mutex_unlock(&relay_channels_mutex);}EXPORT_SYMBOL_GPL(relay_flush);/** *	relay_file_open - open file op for relay files *	@inode: the inode *	@filp: the file * *	Increments the channel buffer refcount. */static int relay_file_open(struct inode *inode, struct file *filp){	struct rchan_buf *buf = inode->i_private;	kref_get(&buf->kref);	filp->private_data = buf;	return nonseekable_open(inode, filp);}/** *	relay_file_mmap - mmap file op for relay files *	@filp: the file *	@vma: the vma describing what to map * *	Calls upon relay_mmap_buf() to map the file into user space. */static int relay_file_mmap(struct file *filp, struct vm_area_struct *vma){	struct rchan_buf *buf = filp->private_data;	return relay_mmap_buf(buf, vma);}/** *	relay_file_poll - poll file op for relay files *	@filp: the file *	@wait: poll table * *	Poll implemention. */static unsigned int relay_file_poll(struct file *filp, poll_table *wait){	unsigned int mask = 0;	struct rchan_buf *buf = filp->private_data;	if (buf->finalized)		return POLLERR;

⌨️ 快捷键说明

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