1
2
3
4
5
6
7
8
9#include <linux/module.h>
10#include <linux/kernel.h>
11#include <linux/fs.h>
12#include <linux/string.h>
13#include <linux/sched.h>
14#include <linux/smp_lock.h>
15
16#include <linux/slab.h>
17
18#include <asm/sn/hwgfs.h>
19
20extern struct vfsmount *hwgfs_vfsmount;
21
22
23
24extern struct dentry *lookup_create(struct nameidata *nd, int is_dir);
25
26static int
27walk_parents_mkdir(
28 const char **path,
29 struct nameidata *nd,
30 int is_dir)
31{
32 char *slash;
33 char buf[strlen(*path)+1];
34 int error;
35
36 while ((slash = strchr(*path, '/')) != NULL) {
37 int len = slash - *path;
38 memcpy(buf, *path, len);
39 buf[len] = '\0';
40
41 error = path_walk(buf, nd);
42 if (unlikely(error))
43 return error;
44
45 nd->dentry = lookup_create(nd, is_dir);
46 if (unlikely(IS_ERR(nd->dentry)))
47 return PTR_ERR(nd->dentry);
48
49 if (!nd->dentry->d_inode)
50 error = vfs_mkdir(nd->dentry->d_parent->d_inode,
51 nd->dentry, 0755);
52
53 up(&nd->dentry->d_parent->d_inode->i_sem);
54 if (unlikely(error))
55 return error;
56
57 *path += len + 1;
58 }
59
60 return 0;
61}
62
63
64static int
65hwgfs_decode(
66 hwgfs_handle_t dir,
67 const char *name,
68 int is_dir,
69 struct inode **parent_inode,
70 struct dentry **dentry)
71{
72 struct nameidata nd;
73 int error;
74
75 if (!dir)
76 dir = hwgfs_vfsmount->mnt_sb->s_root;
77
78 memset(&nd, 0, sizeof(nd));
79 nd.flags = LOOKUP_PARENT;
80 nd.mnt = mntget(hwgfs_vfsmount);
81 nd.dentry = dget(dir);
82
83 error = walk_parents_mkdir(&name, &nd, is_dir);
84 if (unlikely(error))
85 return error;
86
87 error = path_walk(name, &nd);
88 if (unlikely(error))
89 return error;
90
91 *dentry = lookup_create(&nd, is_dir);
92
93 if (unlikely(IS_ERR(*dentry)))
94 return PTR_ERR(*dentry);
95 *parent_inode = (*dentry)->d_parent->d_inode;
96 return 0;
97}
98
99static int
100path_len(
101 struct dentry *de,
102 struct dentry *root)
103{
104 int len = 0;
105
106 while (de != root) {
107 len += de->d_name.len + 1;
108 de = de->d_parent;
109 }
110 return len;
111
112}
113
114int
115hwgfs_generate_path(
116 hwgfs_handle_t de,
117 char *path,
118 int buflen)
119{
120 struct dentry *hwgfs_root;
121 int len;
122 char *path_orig = path;
123
124 if (unlikely(de == NULL))
125 return -EINVAL;
126
127 hwgfs_root = hwgfs_vfsmount->mnt_sb->s_root;
128 if (unlikely(de == hwgfs_root))
129 return -EINVAL;
130
131 spin_lock(&dcache_lock);
132 len = path_len(de, hwgfs_root);
133 if (len > buflen) {
134 spin_unlock(&dcache_lock);
135 return -ENAMETOOLONG;
136 }
137
138 path += len - 1;
139 *path = '\0';
140
141 for (;;) {
142 path -= de->d_name.len;
143 memcpy(path, de->d_name.name, de->d_name.len);
144 de = de->d_parent;
145 if (de == hwgfs_root)
146 break;
147 *(--path) = '/';
148 }
149
150 spin_unlock(&dcache_lock);
151 BUG_ON(path != path_orig);
152 return 0;
153}
154
155hwgfs_handle_t
156hwgfs_register(
157 hwgfs_handle_t dir,
158 const char *name,
159 unsigned int flags,
160 unsigned int major,
161 unsigned int minor,
162 umode_t mode,
163 void *ops,
164 void *info)
165{
166 dev_t devnum = MKDEV(major, minor);
167 struct inode *parent_inode;
168 struct dentry *dentry;
169 int error;
170
171 error = hwgfs_decode(dir, name, 0, &parent_inode, &dentry);
172 if (likely(!error)) {
173 error = vfs_mknod(parent_inode, dentry, mode, devnum);
174 if (likely(!error)) {
175
176
177
178
179 if (S_ISCHR(mode))
180 dentry->d_inode->i_fop = ops;
181 dentry->d_fsdata = info;
182 up(&parent_inode->i_sem);
183 } else {
184 up(&parent_inode->i_sem);
185 dput(dentry);
186 dentry = NULL;
187 }
188 }
189
190 return dentry;
191}
192
193int
194hwgfs_mk_symlink(
195 hwgfs_handle_t dir,
196 const char *name,
197 unsigned int flags,
198 const char *link,
199 hwgfs_handle_t *handle,
200 void *info)
201{
202 struct inode *parent_inode;
203 struct dentry *dentry;
204 int error;
205
206 error = hwgfs_decode(dir, name, 0, &parent_inode, &dentry);
207 if (likely(!error)) {
208 error = vfs_symlink(parent_inode, dentry, link);
209 dentry->d_fsdata = info;
210 if (handle)
211 *handle = dentry;
212 up(&parent_inode->i_sem);
213
214 }
215 return error;
216}
217
218hwgfs_handle_t
219hwgfs_mk_dir(
220 hwgfs_handle_t dir,
221 const char *name,
222 void *info)
223{
224 struct inode *parent_inode;
225 struct dentry *dentry;
226 int error;
227
228 error = hwgfs_decode(dir, name, 1, &parent_inode, &dentry);
229 if (likely(!error)) {
230 error = vfs_mkdir(parent_inode, dentry, 0755);
231 up(&parent_inode->i_sem);
232
233 if (unlikely(error)) {
234 dput(dentry);
235 dentry = NULL;
236 } else {
237 dentry->d_fsdata = info;
238 }
239 }
240 return dentry;
241}
242
243void
244hwgfs_unregister(
245 hwgfs_handle_t de)
246{
247 struct inode *parent_inode = de->d_parent->d_inode;
248
249 if (S_ISDIR(de->d_inode->i_mode))
250 vfs_rmdir(parent_inode, de);
251 else
252 vfs_unlink(parent_inode, de);
253}
254
255
256
257hwgfs_handle_t
258hwgfs_find_handle(
259 hwgfs_handle_t base,
260 const char *name,
261 unsigned int major,
262 unsigned int minor,
263 char type,
264 int traverse_symlinks)
265{
266 struct dentry *dentry = NULL;
267 struct nameidata nd;
268 int error;
269
270 BUG_ON(*name=='/');
271
272 memset(&nd, 0, sizeof(nd));
273
274 nd.mnt = mntget(hwgfs_vfsmount);
275 nd.dentry = dget(base ? base : hwgfs_vfsmount->mnt_sb->s_root);
276 nd.flags = LOOKUP_POSITIVE | (traverse_symlinks ? LOOKUP_FOLLOW : 0);
277
278 error = path_walk(name, &nd);
279 if (likely(!error)) {
280 dentry = nd.dentry;
281 path_release(&nd);
282 }
283
284 return dentry;
285}
286
287hwgfs_handle_t
288hwgfs_get_parent(
289 hwgfs_handle_t de)
290{
291 struct dentry *parent;
292
293 lock_kernel();
294 parent = de->d_parent;
295 unlock_kernel();
296
297 return parent;
298}
299
300int
301hwgfs_set_info(
302 hwgfs_handle_t de,
303 void *info)
304{
305 if (unlikely(de == NULL))
306 return -EINVAL;
307 de->d_fsdata = info;
308 return 0;
309}
310
311void *
312hwgfs_get_info(
313 hwgfs_handle_t de)
314{
315 return de->d_fsdata;
316}
317
318EXPORT_SYMBOL(hwgfs_generate_path);
319EXPORT_SYMBOL(hwgfs_register);
320EXPORT_SYMBOL(hwgfs_unregister);
321EXPORT_SYMBOL(hwgfs_mk_symlink);
322EXPORT_SYMBOL(hwgfs_mk_dir);
323EXPORT_SYMBOL(hwgfs_find_handle);
324EXPORT_SYMBOL(hwgfs_get_parent);
325EXPORT_SYMBOL(hwgfs_set_info);
326EXPORT_SYMBOL(hwgfs_get_info);
327