1
2
3
4
5
6#include <linux/pagemap.h>
7#include <linux/smp_lock.h>
8
9int simple_statfs(struct super_block *sb, struct statfs *buf)
10{
11 buf->f_type = sb->s_magic;
12 buf->f_bsize = PAGE_CACHE_SIZE;
13 buf->f_namelen = NAME_MAX;
14 return 0;
15}
16
17
18
19
20
21
22struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry)
23{
24 d_add(dentry, NULL);
25 return NULL;
26}
27
28int simple_sync_file(struct file * file, struct dentry *dentry, int datasync)
29{
30 return 0;
31}
32
33int dcache_dir_open(struct inode *inode, struct file *file)
34{
35 static struct qstr cursor_name = {.len = 1, .name = "."};
36
37 file->private_data = d_alloc(file->f_dentry, &cursor_name);
38
39 return file->private_data ? 0 : -ENOMEM;
40}
41
42int dcache_dir_close(struct inode *inode, struct file *file)
43{
44 dput(file->private_data);
45 return 0;
46}
47
48loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin)
49{
50 down(&file->f_dentry->d_inode->i_sem);
51 switch (origin) {
52 case 1:
53 offset += file->f_pos;
54 case 0:
55 if (offset >= 0)
56 break;
57 default:
58 up(&file->f_dentry->d_inode->i_sem);
59 return -EINVAL;
60 }
61 if (offset != file->f_pos) {
62 file->f_pos = offset;
63 if (file->f_pos >= 2) {
64 struct list_head *p;
65 struct dentry *cursor = file->private_data;
66 loff_t n = file->f_pos - 2;
67
68 spin_lock(&dcache_lock);
69 p = file->f_dentry->d_subdirs.next;
70 while (n && p != &file->f_dentry->d_subdirs) {
71 struct dentry *next;
72 next = list_entry(p, struct dentry, d_child);
73 if (!list_empty(&next->d_hash) && next->d_inode)
74 n--;
75 p = p->next;
76 }
77 list_del(&cursor->d_child);
78 list_add_tail(&cursor->d_child, p);
79 spin_unlock(&dcache_lock);
80 }
81 }
82 up(&file->f_dentry->d_inode->i_sem);
83 return offset;
84}
85
86
87static inline unsigned char dt_type(struct inode *inode)
88{
89 return (inode->i_mode >> 12) & 15;
90}
91
92
93
94
95
96
97
98int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
99{
100 struct dentry *dentry = filp->f_dentry;
101 struct dentry *cursor = filp->private_data;
102 struct list_head *p, *q = &cursor->d_child;
103 ino_t ino;
104 int i = filp->f_pos;
105
106 switch (i) {
107 case 0:
108 ino = dentry->d_inode->i_ino;
109 if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
110 break;
111 filp->f_pos++;
112 i++;
113
114 case 1:
115 ino = parent_ino(dentry);
116 if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
117 break;
118 filp->f_pos++;
119 i++;
120
121 default:
122 spin_lock(&dcache_lock);
123 if (filp->f_pos == 2) {
124 list_del(q);
125 list_add(q, &dentry->d_subdirs);
126 }
127 for (p=q->next; p != &dentry->d_subdirs; p=p->next) {
128 struct dentry *next;
129 next = list_entry(p, struct dentry, d_child);
130 if (list_empty(&next->d_hash) || !next->d_inode)
131 continue;
132
133 spin_unlock(&dcache_lock);
134 if (filldir(dirent, next->d_name.name, next->d_name.len, filp->f_pos, next->d_inode->i_ino, dt_type(next->d_inode)) < 0)
135 return 0;
136 spin_lock(&dcache_lock);
137
138 list_del(q);
139 list_add(q, p);
140 p = q;
141 filp->f_pos++;
142 }
143 spin_unlock(&dcache_lock);
144 }
145 return 0;
146}
147
148ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos)
149{
150 return -EISDIR;
151}
152
153struct file_operations simple_dir_operations = {
154 .open = dcache_dir_open,
155 .release = dcache_dir_close,
156 .llseek = dcache_dir_lseek,
157 .read = generic_read_dir,
158 .readdir = dcache_readdir,
159};
160
161struct inode_operations simple_dir_inode_operations = {
162 .lookup = simple_lookup,
163};
164
165
166
167
168
169struct super_block *
170get_sb_pseudo(struct file_system_type *fs_type, char *name,
171 struct super_operations *ops, unsigned long magic)
172{
173 struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
174 static struct super_operations default_ops = {.statfs = simple_statfs};
175 struct dentry *dentry;
176 struct inode *root;
177 struct qstr d_name = {.name = name, .len = strlen(name)};
178
179 if (IS_ERR(s))
180 return s;
181
182 s->s_flags = MS_NOUSER;
183 s->s_maxbytes = ~0ULL;
184 s->s_blocksize = 1024;
185 s->s_blocksize_bits = 10;
186 s->s_magic = magic;
187 s->s_op = ops ? ops : &default_ops;
188 root = new_inode(s);
189 if (!root)
190 goto Enomem;
191 root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
192 root->i_uid = root->i_gid = 0;
193 root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
194 dentry = d_alloc(NULL, &d_name);
195 if (!dentry) {
196 iput(root);
197 goto Enomem;
198 }
199 dentry->d_sb = s;
200 dentry->d_parent = dentry;
201 d_instantiate(dentry, root);
202 s->s_root = dentry;
203 s->s_flags |= MS_ACTIVE;
204 return s;
205
206Enomem:
207 up_write(&s->s_umount);
208 deactivate_super(s);
209 return ERR_PTR(-ENOMEM);
210}
211