Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/*
  2 * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  3 * Licensed under the GPL
  4 */
  5
  6#include <linux/ctype.h>
  7#include <linux/dcache.h>
  8#include <linux/file.h>
  9#include <linux/fs.h>
 10#include <linux/init.h>
 11#include <linux/kernel.h>
 12#include <linux/list.h>
 13#include <linux/module.h>
 14#include <linux/mount.h>
 15#include <linux/slab.h>
 16#include <linux/statfs.h>
 17#include <linux/types.h>
 18#include <linux/pid_namespace.h>
 19#include <linux/namei.h>
 20#include <asm/uaccess.h>
 21#include <os.h>
 22
 23static struct inode *get_inode(struct super_block *, struct dentry *);
 24
 25struct hppfs_data {
 26	struct list_head list;
 27	char contents[PAGE_SIZE - sizeof(struct list_head)];
 28};
 29
 30struct hppfs_private {
 31	struct file *proc_file;
 32	int host_fd;
 33	loff_t len;
 34	struct hppfs_data *contents;
 35};
 36
 37struct hppfs_inode_info {
 38	struct dentry *proc_dentry;
 39	struct inode vfs_inode;
 40};
 41
 42static inline struct hppfs_inode_info *HPPFS_I(struct inode *inode)
 43{
 44	return container_of(inode, struct hppfs_inode_info, vfs_inode);
 45}
 46
 47#define HPPFS_SUPER_MAGIC 0xb00000ee
 48
 49static const struct super_operations hppfs_sbops;
 50
 51static int is_pid(struct dentry *dentry)
 52{
 53	struct super_block *sb;
 54	int i;
 55
 56	sb = dentry->d_sb;
 57	if (dentry->d_parent != sb->s_root)
 58		return 0;
 59
 60	for (i = 0; i < dentry->d_name.len; i++) {
 61		if (!isdigit(dentry->d_name.name[i]))
 62			return 0;
 63	}
 64	return 1;
 65}
 66
 67static char *dentry_name(struct dentry *dentry, int extra)
 68{
 69	struct dentry *parent;
 70	char *root, *name;
 71	const char *seg_name;
 72	int len, seg_len, root_len;
 73
 74	len = 0;
 75	parent = dentry;
 76	while (parent->d_parent != parent) {
 77		if (is_pid(parent))
 78			len += strlen("pid") + 1;
 79		else len += parent->d_name.len + 1;
 80		parent = parent->d_parent;
 81	}
 82
 83	root = "proc";
 84	root_len = strlen(root);
 85	len += root_len;
 86	name = kmalloc(len + extra + 1, GFP_KERNEL);
 87	if (name == NULL)
 88		return NULL;
 89
 90	name[len] = '\0';
 91	parent = dentry;
 92	while (parent->d_parent != parent) {
 93		if (is_pid(parent)) {
 94			seg_name = "pid";
 95			seg_len = strlen(seg_name);
 96		}
 97		else {
 98			seg_name = parent->d_name.name;
 99			seg_len = parent->d_name.len;
100		}
101
102		len -= seg_len + 1;
103		name[len] = '/';
104		memcpy(&name[len + 1], seg_name, seg_len);
105		parent = parent->d_parent;
106	}
107	memcpy(name, root, root_len);
108	return name;
109}
110
111static int file_removed(struct dentry *dentry, const char *file)
112{
113	char *host_file;
114	int extra, fd;
115
116	extra = 0;
117	if (file != NULL)
118		extra += strlen(file) + 1;
119
120	host_file = dentry_name(dentry, extra + strlen("/remove"));
121	if (host_file == NULL) {
122		printk(KERN_ERR "file_removed : allocation failed\n");
123		return -ENOMEM;
124	}
125
126	if (file != NULL) {
127		strcat(host_file, "/");
128		strcat(host_file, file);
129	}
130	strcat(host_file, "/remove");
131
132	fd = os_open_file(host_file, of_read(OPENFLAGS()), 0);
133	kfree(host_file);
134	if (fd > 0) {
135		os_close_file(fd);
136		return 1;
137	}
138	return 0;
139}
140
141static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
142				   unsigned int flags)
143{
144	struct dentry *proc_dentry, *parent;
145	struct qstr *name = &dentry->d_name;
146	struct inode *inode;
147	int err, deleted;
148
149	deleted = file_removed(dentry, NULL);
150	if (deleted < 0)
151		return ERR_PTR(deleted);
152	else if (deleted)
153		return ERR_PTR(-ENOENT);
154
155	parent = HPPFS_I(ino)->proc_dentry;
156	mutex_lock(&parent->d_inode->i_mutex);
157	proc_dentry = lookup_one_len(name->name, parent, name->len);
158	mutex_unlock(&parent->d_inode->i_mutex);
159
160	if (IS_ERR(proc_dentry))
161		return proc_dentry;
162
163	err = -ENOMEM;
164	inode = get_inode(ino->i_sb, proc_dentry);
165	if (!inode)
166		goto out;
167
168 	d_add(dentry, inode);
169	return NULL;
170
171 out:
172	return ERR_PTR(err);
173}
174
175static const struct inode_operations hppfs_file_iops = {
176};
177
178static ssize_t read_proc(struct file *file, char __user *buf, ssize_t count,
179			 loff_t *ppos, int is_user)
180{
181	ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
182	ssize_t n;
183
184	read = file_inode(file)->i_fop->read;
185
186	if (!is_user)
187		set_fs(KERNEL_DS);
188
189	n = (*read)(file, buf, count, &file->f_pos);
190
191	if (!is_user)
192		set_fs(USER_DS);
193
194	if (ppos)
195		*ppos = file->f_pos;
196	return n;
197}
198
199static ssize_t hppfs_read_file(int fd, char __user *buf, ssize_t count)
200{
201	ssize_t n;
202	int cur, err;
203	char *new_buf;
204
205	n = -ENOMEM;
206	new_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
207	if (new_buf == NULL) {
208		printk(KERN_ERR "hppfs_read_file : kmalloc failed\n");
209		goto out;
210	}
211	n = 0;
212	while (count > 0) {
213		cur = min_t(ssize_t, count, PAGE_SIZE);
214		err = os_read_file(fd, new_buf, cur);
215		if (err < 0) {
216			printk(KERN_ERR "hppfs_read : read failed, "
217			       "errno = %d\n", err);
218			n = err;
219			goto out_free;
220		} else if (err == 0)
221			break;
222
223		if (copy_to_user(buf, new_buf, err)) {
224			n = -EFAULT;
225			goto out_free;
226		}
227		n += err;
228		count -= err;
229	}
230 out_free:
231	kfree(new_buf);
232 out:
233	return n;
234}
235
236static ssize_t hppfs_read(struct file *file, char __user *buf, size_t count,
237			  loff_t *ppos)
238{
239	struct hppfs_private *hppfs = file->private_data;
240	struct hppfs_data *data;
241	loff_t off;
242	int err;
243
244	if (hppfs->contents != NULL) {
245		int rem;
246
247		if (*ppos >= hppfs->len)
248			return 0;
249
250		data = hppfs->contents;
251		off = *ppos;
252		while (off >= sizeof(data->contents)) {
253			data = list_entry(data->list.next, struct hppfs_data,
254					  list);
255			off -= sizeof(data->contents);
256		}
257
258		if (off + count > hppfs->len)
259			count = hppfs->len - off;
260		rem = copy_to_user(buf, &data->contents[off], count);
261		*ppos += count - rem;
262		if (rem > 0)
263			return -EFAULT;
264	} else if (hppfs->host_fd != -1) {
265		err = os_seek_file(hppfs->host_fd, *ppos);
266		if (err) {
267			printk(KERN_ERR "hppfs_read : seek failed, "
268			       "errno = %d\n", err);
269			return err;
270		}
271		err = hppfs_read_file(hppfs->host_fd, buf, count);
272		if (err < 0) {
273			printk(KERN_ERR "hppfs_read: read failed: %d\n", err);
274			return err;
275		}
276		count = err;
277		if (count > 0)
278			*ppos += count;
279	}
280	else count = read_proc(hppfs->proc_file, buf, count, ppos, 1);
281
282	return count;
283}
284
285static ssize_t hppfs_write(struct file *file, const char __user *buf,
286			   size_t len, loff_t *ppos)
287{
288	struct hppfs_private *data = file->private_data;
289	struct file *proc_file = data->proc_file;
290	ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
291
292	write = file_inode(proc_file)->i_fop->write;
293	return (*write)(proc_file, buf, len, ppos);
294}
295
296static int open_host_sock(char *host_file, int *filter_out)
297{
298	char *end;
299	int fd;
300
301	end = &host_file[strlen(host_file)];
302	strcpy(end, "/rw");
303	*filter_out = 1;
304	fd = os_connect_socket(host_file);
305	if (fd > 0)
306		return fd;
307
308	strcpy(end, "/r");
309	*filter_out = 0;
310	fd = os_connect_socket(host_file);
311	return fd;
312}
313
314static void free_contents(struct hppfs_data *head)
315{
316	struct hppfs_data *data;
317	struct list_head *ele, *next;
318
319	if (head == NULL)
320		return;
321
322	list_for_each_safe(ele, next, &head->list) {
323		data = list_entry(ele, struct hppfs_data, list);
324		kfree(data);
325	}
326	kfree(head);
327}
328
329static struct hppfs_data *hppfs_get_data(int fd, int filter,
330					 struct file *proc_file,
331					 struct file *hppfs_file,
332					 loff_t *size_out)
333{
334	struct hppfs_data *data, *new, *head;
335	int n, err;
336
337	err = -ENOMEM;
338	data = kmalloc(sizeof(*data), GFP_KERNEL);
339	if (data == NULL) {
340		printk(KERN_ERR "hppfs_get_data : head allocation failed\n");
341		goto failed;
342	}
343
344	INIT_LIST_HEAD(&data->list);
345
346	head = data;
347	*size_out = 0;
348
349	if (filter) {
350		while ((n = read_proc(proc_file, data->contents,
351				      sizeof(data->contents), NULL, 0)) > 0)
352			os_write_file(fd, data->contents, n);
353		err = os_shutdown_socket(fd, 0, 1);
354		if (err) {
355			printk(KERN_ERR "hppfs_get_data : failed to shut down "
356			       "socket\n");
357			goto failed_free;
358		}
359	}
360	while (1) {
361		n = os_read_file(fd, data->contents, sizeof(data->contents));
362		if (n < 0) {
363			err = n;
364			printk(KERN_ERR "hppfs_get_data : read failed, "
365			       "errno = %d\n", err);
366			goto failed_free;
367		} else if (n == 0)
368			break;
369
370		*size_out += n;
371
372		if (n < sizeof(data->contents))
373			break;
374
375		new = kmalloc(sizeof(*data), GFP_KERNEL);
376		if (new == 0) {
377			printk(KERN_ERR "hppfs_get_data : data allocation "
378			       "failed\n");
379			err = -ENOMEM;
380			goto failed_free;
381		}
382
383		INIT_LIST_HEAD(&new->list);
384		list_add(&new->list, &data->list);
385		data = new;
386	}
387	return head;
388
389 failed_free:
390	free_contents(head);
391 failed:
392	return ERR_PTR(err);
393}
394
395static struct hppfs_private *hppfs_data(void)
396{
397	struct hppfs_private *data;
398
399	data = kmalloc(sizeof(*data), GFP_KERNEL);
400	if (data == NULL)
401		return data;
402
403	*data = ((struct hppfs_private ) { .host_fd  		= -1,
404					   .len  		= -1,
405					   .contents 		= NULL } );
406	return data;
407}
408
409static int file_mode(int fmode)
410{
411	if (fmode == (FMODE_READ | FMODE_WRITE))
412		return O_RDWR;
413	if (fmode == FMODE_READ)
414		return O_RDONLY;
415	if (fmode == FMODE_WRITE)
416		return O_WRONLY;
417	return 0;
418}
419
420static int hppfs_open(struct inode *inode, struct file *file)
421{
422	const struct cred *cred = file->f_cred;
423	struct hppfs_private *data;
424	struct path path;
425	char *host_file;
426	int err, fd, type, filter;
427
428	err = -ENOMEM;
429	data = hppfs_data();
430	if (data == NULL)
431		goto out;
432
433	host_file = dentry_name(file->f_path.dentry, strlen("/rw"));
434	if (host_file == NULL)
435		goto out_free2;
436
437	path.mnt = inode->i_sb->s_fs_info;
438	path.dentry = HPPFS_I(inode)->proc_dentry;
439
440	data->proc_file = dentry_open(&path, file_mode(file->f_mode), cred);
441	err = PTR_ERR(data->proc_file);
442	if (IS_ERR(data->proc_file))
443		goto out_free1;
444
445	type = os_file_type(host_file);
446	if (type == OS_TYPE_FILE) {
447		fd = os_open_file(host_file, of_read(OPENFLAGS()), 0);
448		if (fd >= 0)
449			data->host_fd = fd;
450		else
451			printk(KERN_ERR "hppfs_open : failed to open '%s', "
452			       "errno = %d\n", host_file, -fd);
453
454		data->contents = NULL;
455	} else if (type == OS_TYPE_DIR) {
456		fd = open_host_sock(host_file, &filter);
457		if (fd > 0) {
458			data->contents = hppfs_get_data(fd, filter,
459							data->proc_file,
460							file, &data->len);
461			if (!IS_ERR(data->contents))
462				data->host_fd = fd;
463		} else
464			printk(KERN_ERR "hppfs_open : failed to open a socket "
465			       "in '%s', errno = %d\n", host_file, -fd);
466	}
467	kfree(host_file);
468
469	file->private_data = data;
470	return 0;
471
472 out_free1:
473	kfree(host_file);
474 out_free2:
475	free_contents(data->contents);
476	kfree(data);
477 out:
478	return err;
479}
480
481static int hppfs_dir_open(struct inode *inode, struct file *file)
482{
483	const struct cred *cred = file->f_cred;
484	struct hppfs_private *data;
485	struct path path;
486	int err;
487
488	err = -ENOMEM;
489	data = hppfs_data();
490	if (data == NULL)
491		goto out;
492
493	path.mnt = inode->i_sb->s_fs_info;
494	path.dentry = HPPFS_I(inode)->proc_dentry;
495	data->proc_file = dentry_open(&path, file_mode(file->f_mode), cred);
496	err = PTR_ERR(data->proc_file);
497	if (IS_ERR(data->proc_file))
498		goto out_free;
499
500	file->private_data = data;
501	return 0;
502
503 out_free:
504	kfree(data);
505 out:
506	return err;
507}
508
509static loff_t hppfs_llseek(struct file *file, loff_t off, int where)
510{
511	struct hppfs_private *data = file->private_data;
512	struct file *proc_file = data->proc_file;
513	loff_t (*llseek)(struct file *, loff_t, int);
514	loff_t ret;
515
516	llseek = file_inode(proc_file)->i_fop->llseek;
517	if (llseek != NULL) {
518		ret = (*llseek)(proc_file, off, where);
519		if (ret < 0)
520			return ret;
521	}
522
523	return default_llseek(file, off, where);
524}
525
526static int hppfs_release(struct inode *inode, struct file *file)
527{
528	struct hppfs_private *data = file->private_data;
529	struct file *proc_file = data->proc_file;
530	if (proc_file)
531		fput(proc_file);
532	kfree(data);
533	return 0;
534}
535
536static const struct file_operations hppfs_file_fops = {
537	.owner		= NULL,
538	.llseek		= hppfs_llseek,
539	.read		= hppfs_read,
540	.write		= hppfs_write,
541	.open		= hppfs_open,
542	.release	= hppfs_release,
543};
544
545struct hppfs_dirent {
546	struct dir_context ctx;
547	struct dir_context *caller;
548	struct dentry *dentry;
549};
550
551static int hppfs_filldir(void *d, const char *name, int size,
552			 loff_t offset, u64 inode, unsigned int type)
553{
554	struct hppfs_dirent *dirent = d;
555
556	if (file_removed(dirent->dentry, name))
557		return 0;
558
559	dirent->caller->pos = dirent->ctx.pos;
560	return !dir_emit(dirent->caller, name, size, inode, type);
561}
562
563static int hppfs_readdir(struct file *file, struct dir_context *ctx)
564{
565	struct hppfs_private *data = file->private_data;
566	struct file *proc_file = data->proc_file;
567	struct hppfs_dirent d = {
568		.ctx.actor	= hppfs_filldir,
569		.caller		= ctx,
570		.dentry  	= file->f_path.dentry
571	};
572	int err;
573	proc_file->f_pos = ctx->pos;
574	err = iterate_dir(proc_file, &d.ctx);
575	ctx->pos = d.ctx.pos;
576	return err;
577}
578
579static const struct file_operations hppfs_dir_fops = {
580	.owner		= NULL,
581	.iterate	= hppfs_readdir,
582	.open		= hppfs_dir_open,
583	.llseek		= default_llseek,
584	.release	= hppfs_release,
585};
586
587static int hppfs_statfs(struct dentry *dentry, struct kstatfs *sf)
588{
589	sf->f_blocks = 0;
590	sf->f_bfree = 0;
591	sf->f_bavail = 0;
592	sf->f_files = 0;
593	sf->f_ffree = 0;
594	sf->f_type = HPPFS_SUPER_MAGIC;
595	return 0;
596}
597
598static struct inode *hppfs_alloc_inode(struct super_block *sb)
599{
600	struct hppfs_inode_info *hi;
601
602	hi = kmalloc(sizeof(*hi), GFP_KERNEL);
603	if (!hi)
604		return NULL;
605
606	hi->proc_dentry = NULL;
607	inode_init_once(&hi->vfs_inode);
608	return &hi->vfs_inode;
609}
610
611void hppfs_evict_inode(struct inode *ino)
612{
613	clear_inode(ino);
614	dput(HPPFS_I(ino)->proc_dentry);
615	mntput(ino->i_sb->s_fs_info);
616}
617
618static void hppfs_i_callback(struct rcu_head *head)
619{
620	struct inode *inode = container_of(head, struct inode, i_rcu);
621	kfree(HPPFS_I(inode));
622}
623
624static void hppfs_destroy_inode(struct inode *inode)
625{
626	call_rcu(&inode->i_rcu, hppfs_i_callback);
627}
628
629static const struct super_operations hppfs_sbops = {
630	.alloc_inode	= hppfs_alloc_inode,
631	.destroy_inode	= hppfs_destroy_inode,
632	.evict_inode	= hppfs_evict_inode,
633	.statfs		= hppfs_statfs,
634};
635
636static int hppfs_readlink(struct dentry *dentry, char __user *buffer,
637			  int buflen)
638{
639	struct dentry *proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
640	return proc_dentry->d_inode->i_op->readlink(proc_dentry, buffer,
641						    buflen);
642}
643
644static void *hppfs_follow_link(struct dentry *dentry, struct nameidata *nd)
645{
646	struct dentry *proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
647
648	return proc_dentry->d_inode->i_op->follow_link(proc_dentry, nd);
649}
650
651static void hppfs_put_link(struct dentry *dentry, struct nameidata *nd,
652			   void *cookie)
653{
654	struct dentry *proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
655
656	if (proc_dentry->d_inode->i_op->put_link)
657		proc_dentry->d_inode->i_op->put_link(proc_dentry, nd, cookie);
658}
659
660static const struct inode_operations hppfs_dir_iops = {
661	.lookup		= hppfs_lookup,
662};
663
664static const struct inode_operations hppfs_link_iops = {
665	.readlink	= hppfs_readlink,
666	.follow_link	= hppfs_follow_link,
667	.put_link	= hppfs_put_link,
668};
669
670static struct inode *get_inode(struct super_block *sb, struct dentry *dentry)
671{
672	struct inode *proc_ino = dentry->d_inode;
673	struct inode *inode = new_inode(sb);
674
675	if (!inode) {
676		dput(dentry);
677		return NULL;
678	}
679
680	if (S_ISDIR(dentry->d_inode->i_mode)) {
681		inode->i_op = &hppfs_dir_iops;
682		inode->i_fop = &hppfs_dir_fops;
683	} else if (S_ISLNK(dentry->d_inode->i_mode)) {
684		inode->i_op = &hppfs_link_iops;
685		inode->i_fop = &hppfs_file_fops;
686	} else {
687		inode->i_op = &hppfs_file_iops;
688		inode->i_fop = &hppfs_file_fops;
689	}
690
691	HPPFS_I(inode)->proc_dentry = dentry;
692
693	inode->i_uid = proc_ino->i_uid;
694	inode->i_gid = proc_ino->i_gid;
695	inode->i_atime = proc_ino->i_atime;
696	inode->i_mtime = proc_ino->i_mtime;
697	inode->i_ctime = proc_ino->i_ctime;
698	inode->i_ino = proc_ino->i_ino;
699	inode->i_mode = proc_ino->i_mode;
700	set_nlink(inode, proc_ino->i_nlink);
701	inode->i_size = proc_ino->i_size;
702	inode->i_blocks = proc_ino->i_blocks;
703
704	return inode;
705}
706
707static int hppfs_fill_super(struct super_block *sb, void *d, int silent)
708{
709	struct inode *root_inode;
710	struct vfsmount *proc_mnt;
711	int err = -ENOENT;
712
713	proc_mnt = mntget(task_active_pid_ns(current)->proc_mnt);
714	if (IS_ERR(proc_mnt))
715		goto out;
716
717	sb->s_blocksize = 1024;
718	sb->s_blocksize_bits = 10;
719	sb->s_magic = HPPFS_SUPER_MAGIC;
720	sb->s_op = &hppfs_sbops;
721	sb->s_fs_info = proc_mnt;
722
723	err = -ENOMEM;
724	root_inode = get_inode(sb, dget(proc_mnt->mnt_root));
725	sb->s_root = d_make_root(root_inode);
726	if (!sb->s_root)
727		goto out_mntput;
728
729	return 0;
730
731 out_mntput:
732	mntput(proc_mnt);
733 out:
734	return(err);
735}
736
737static struct dentry *hppfs_read_super(struct file_system_type *type,
738			    int flags, const char *dev_name,
739			    void *data)
740{
741	return mount_nodev(type, flags, data, hppfs_fill_super);
742}
743
744static struct file_system_type hppfs_type = {
745	.owner 		= THIS_MODULE,
746	.name 		= "hppfs",
747	.mount 		= hppfs_read_super,
748	.kill_sb	= kill_anon_super,
749	.fs_flags 	= 0,
750};
751MODULE_ALIAS_FS("hppfs");
752
753static int __init init_hppfs(void)
754{
755	return register_filesystem(&hppfs_type);
756}
757
758static void __exit exit_hppfs(void)
759{
760	unregister_filesystem(&hppfs_type);
761}
762
763module_init(init_hppfs)
764module_exit(exit_hppfs)
765MODULE_LICENSE("GPL");