original comment: +Wilson03172004,marked due to this pci host does not support MWI
[linux-2.4.git] / fs / proc / inode.c
1 /*
2  *  linux/fs/proc/inode.c
3  *
4  *  Copyright (C) 1991, 1992  Linus Torvalds
5  */
6
7 #include <linux/sched.h>
8 #include <linux/proc_fs.h>
9 #include <linux/kernel.h>
10 #include <linux/mm.h>
11 #include <linux/string.h>
12 #include <linux/stat.h>
13 #include <linux/file.h>
14 #include <linux/locks.h>
15 #include <linux/limits.h>
16 #define __NO_VERSION__
17 #include <linux/module.h>
18 #include <linux/smp_lock.h>
19
20 #include <asm/system.h>
21 #include <asm/uaccess.h>
22
23 extern void free_proc_entry(struct proc_dir_entry *);
24
25 static inline struct proc_dir_entry * de_get(struct proc_dir_entry *de)
26 {
27         if (de)
28                 atomic_inc(&de->count);
29         return de;
30 }
31
32 /*
33  * Decrements the use count and checks for deferred deletion.
34  */
35 static void de_put(struct proc_dir_entry *de)
36 {
37         if (de) {       
38                 lock_kernel();          
39                 if (!atomic_read(&de->count)) {
40                         printk("de_put: entry %s already free!\n", de->name);
41                         unlock_kernel();
42                         return;
43                 }
44
45                 if (atomic_dec_and_test(&de->count)) {
46                         if (de->deleted) {
47                                 printk("de_put: deferred delete of %s\n",
48                                         de->name);
49                                 free_proc_entry(de);
50                         }
51                 }               
52                 unlock_kernel();
53         }
54 }
55
56 /*
57  * Decrement the use count of the proc_dir_entry.
58  */
59 static void proc_delete_inode(struct inode *inode)
60 {
61         struct proc_dir_entry *de = inode->u.generic_ip;
62
63         inode->i_state = I_CLEAR;
64
65         if (PROC_INODE_PROPER(inode)) {
66                 proc_pid_delete_inode(inode);
67                 return;
68         }
69         if (de) {
70                 if (de->owner)
71                         __MOD_DEC_USE_COUNT(de->owner);
72                 de_put(de);
73         }
74 }
75
76 struct vfsmount *proc_mnt;
77
78 static void proc_read_inode(struct inode * inode)
79 {
80         inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
81 }
82
83 static int proc_statfs(struct super_block *sb, struct statfs *buf)
84 {
85         buf->f_type = PROC_SUPER_MAGIC;
86         buf->f_bsize = PAGE_SIZE/sizeof(long);
87         buf->f_bfree = 0;
88         buf->f_bavail = 0;
89         buf->f_ffree = 0;
90         buf->f_namelen = NAME_MAX;
91         return 0;
92 }
93
94 static struct super_operations proc_sops = { 
95         read_inode:     proc_read_inode,
96         put_inode:      force_delete,
97         delete_inode:   proc_delete_inode,
98         statfs:         proc_statfs,
99 };
100
101
102 static int parse_options(char *options,uid_t *uid,gid_t *gid)
103 {
104         char *this_char,*value;
105
106         *uid = current->uid;
107         *gid = current->gid;
108         if (!options) return 1;
109         for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
110                 if ((value = strchr(this_char,'=')) != NULL)
111                         *value++ = 0;
112                 if (!strcmp(this_char,"uid")) {
113                         if (!value || !*value)
114                                 return 0;
115                         *uid = simple_strtoul(value,&value,0);
116                         if (*value)
117                                 return 0;
118                 }
119                 else if (!strcmp(this_char,"gid")) {
120                         if (!value || !*value)
121                                 return 0;
122                         *gid = simple_strtoul(value,&value,0);
123                         if (*value)
124                                 return 0;
125                 }
126                 else return 1;
127         }
128         return 1;
129 }
130
131 struct inode * proc_get_inode(struct super_block * sb, int ino,
132                                 struct proc_dir_entry * de)
133 {
134         struct inode * inode;
135
136         /*
137          * Increment the use count so the dir entry can't disappear.
138          */
139         de_get(de);
140 #if 1
141 /* shouldn't ever happen */
142 if (de && de->deleted)
143 printk("proc_iget: using deleted entry %s, count=%d\n", de->name, atomic_read(&de->count));
144 #endif
145
146         inode = iget(sb, ino);
147         if (!inode)
148                 goto out_fail;
149         
150         inode->u.generic_ip = (void *) de;
151         if (de) {
152                 if (de->mode) {
153                         inode->i_mode = de->mode;
154                         inode->i_uid = de->uid;
155                         inode->i_gid = de->gid;
156                 }
157                 if (de->size)
158                         inode->i_size = de->size;
159                 if (de->nlink)
160                         inode->i_nlink = de->nlink;
161                 if (de->owner)
162                         __MOD_INC_USE_COUNT(de->owner);
163                 if (de->proc_iops)
164                         inode->i_op = de->proc_iops;
165                 if (de->proc_fops)
166                         inode->i_fop = de->proc_fops;
167                 else if (S_ISBLK(de->mode)||S_ISCHR(de->mode)||S_ISFIFO(de->mode))
168                         init_special_inode(inode,de->mode,kdev_t_to_nr(de->rdev));
169         }
170
171 out:
172         return inode;
173
174 out_fail:
175         de_put(de);
176         goto out;
177 }                       
178
179 struct super_block *proc_read_super(struct super_block *s,void *data, 
180                                     int silent)
181 {
182         struct inode * root_inode;
183         struct task_struct *p;
184
185         s->s_blocksize = 1024;
186         s->s_blocksize_bits = 10;
187         s->s_magic = PROC_SUPER_MAGIC;
188         s->s_op = &proc_sops;
189         s->s_maxbytes = ~0UL;
190         
191         root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root);
192         if (!root_inode)
193                 goto out_no_root;
194         /*
195          * Fixup the root inode's nlink value
196          */
197         read_lock(&tasklist_lock);
198         for_each_task(p) if (p->pid) root_inode->i_nlink++;
199         read_unlock(&tasklist_lock);
200         s->s_root = d_alloc_root(root_inode);
201         if (!s->s_root)
202                 goto out_no_root;
203         parse_options(data, &root_inode->i_uid, &root_inode->i_gid);
204         return s;
205
206 out_no_root:
207         printk("proc_read_super: get root inode failed\n");
208         iput(root_inode);
209         return NULL;
210 }
211 MODULE_LICENSE("GPL");