initial commit with v2.6.9
[linux-2.6.9-moxart.git] / arch / ia64 / sn / io / hwgfs / interface.c
blob4e19418053c9108298275a0f9ccf7ba18437f804
1 /*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
6 * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved.
8 * Portions based on Adam Richter's smalldevfs and thus
9 * Copyright 2002-2003 Yggdrasil Computing, Inc.
12 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/fs.h>
15 #include <linux/mount.h>
16 #include <linux/namei.h>
17 #include <linux/string.h>
18 #include <linux/slab.h>
19 #include <asm/sn/hwgfs.h>
22 extern struct vfsmount *hwgfs_vfsmount;
24 static int
25 walk_parents_mkdir(
26 const char **path,
27 struct nameidata *nd,
28 int is_dir)
30 char *slash;
31 char buf[strlen(*path)+1];
32 int error;
34 while ((slash = strchr(*path, '/')) != NULL) {
35 int len = slash - *path;
36 memcpy(buf, *path, len);
37 buf[len] = '\0';
39 error = path_walk(buf, nd);
40 if (unlikely(error))
41 return error;
43 nd->dentry = lookup_create(nd, is_dir);
44 nd->flags |= LOOKUP_PARENT;
45 if (IS_ERR(nd->dentry))
46 return PTR_ERR(nd->dentry);
48 if (!nd->dentry->d_inode)
49 error = vfs_mkdir(nd->dentry->d_parent->d_inode,
50 nd->dentry, 0755);
52 up(&nd->dentry->d_parent->d_inode->i_sem);
53 if (unlikely(error))
54 return error;
56 *path += len + 1;
59 return 0;
62 /* On success, returns with parent_inode->i_sem taken. */
63 static int
64 hwgfs_decode(
65 hwgfs_handle_t dir,
66 const char *name,
67 int is_dir,
68 struct inode **parent_inode,
69 struct dentry **dentry)
71 struct nameidata nd;
72 int error;
74 if (!dir)
75 dir = hwgfs_vfsmount->mnt_sb->s_root;
77 memset(&nd, 0, sizeof(nd));
78 nd.flags = LOOKUP_PARENT;
79 nd.mnt = mntget(hwgfs_vfsmount);
80 nd.dentry = dget(dir);
82 error = walk_parents_mkdir(&name, &nd, is_dir);
83 if (unlikely(error))
84 return error;
86 error = path_walk(name, &nd);
87 if (unlikely(error))
88 return error;
90 *dentry = lookup_create(&nd, is_dir);
92 if (IS_ERR(*dentry))
93 return PTR_ERR(*dentry);
94 *parent_inode = (*dentry)->d_parent->d_inode;
95 return 0;
98 static int
99 path_len(
100 struct dentry *de,
101 struct dentry *root)
103 int len = 0;
105 while (de != root) {
106 len += de->d_name.len + 1; /* count the '/' */
107 de = de->d_parent;
109 return len; /* -1 because we omit the leading '/',
110 +1 because we include trailing '\0' */
114 hwgfs_generate_path(
115 hwgfs_handle_t de,
116 char *path,
117 int buflen)
119 struct dentry *hwgfs_root;
120 int len;
121 char *path_orig = path;
123 if (unlikely(de == NULL))
124 return -EINVAL;
126 hwgfs_root = hwgfs_vfsmount->mnt_sb->s_root;
127 if (unlikely(de == hwgfs_root))
128 return -EINVAL;
130 spin_lock(&dcache_lock);
131 len = path_len(de, hwgfs_root);
132 if (len > buflen) {
133 spin_unlock(&dcache_lock);
134 return -ENAMETOOLONG;
137 path += len - 1;
138 *path = '\0';
140 for (;;) {
141 path -= de->d_name.len;
142 memcpy(path, de->d_name.name, de->d_name.len);
143 de = de->d_parent;
144 if (de == hwgfs_root)
145 break;
146 *(--path) = '/';
149 spin_unlock(&dcache_lock);
150 BUG_ON(path != path_orig);
151 return 0;
154 hwgfs_handle_t
155 hwgfs_register(
156 hwgfs_handle_t dir,
157 const char *name,
158 unsigned int flags,
159 unsigned int major,
160 unsigned int minor,
161 umode_t mode,
162 void *ops,
163 void *info)
165 dev_t devnum = MKDEV(major, minor);
166 struct inode *parent_inode;
167 struct dentry *dentry;
168 int error;
170 error = hwgfs_decode(dir, name, 0, &parent_inode, &dentry);
171 if (likely(!error)) {
172 error = vfs_mknod(parent_inode, dentry, mode, devnum);
173 if (likely(!error)) {
175 * Do this inside parents i_sem to avoid racing
176 * with lookups.
178 if (S_ISCHR(mode))
179 dentry->d_inode->i_fop = ops;
180 dentry->d_fsdata = info;
181 up(&parent_inode->i_sem);
182 } else {
183 up(&parent_inode->i_sem);
184 dput(dentry);
185 dentry = NULL;
189 return dentry;
193 hwgfs_mk_symlink(
194 hwgfs_handle_t dir,
195 const char *name,
196 unsigned int flags,
197 const char *link,
198 hwgfs_handle_t *handle,
199 void *info)
201 struct inode *parent_inode;
202 struct dentry *dentry;
203 int error;
205 error = hwgfs_decode(dir, name, 0, &parent_inode, &dentry);
206 if (likely(!error)) {
207 error = vfs_symlink(parent_inode, dentry, link, S_IALLUGO);
208 dentry->d_fsdata = info;
209 if (handle)
210 *handle = dentry;
211 up(&parent_inode->i_sem);
212 /* dput(dentry); */
214 return error;
217 hwgfs_handle_t
218 hwgfs_mk_dir(
219 hwgfs_handle_t dir,
220 const char *name,
221 void *info)
223 struct inode *parent_inode;
224 struct dentry *dentry;
225 int error;
227 error = hwgfs_decode(dir, name, 1, &parent_inode, &dentry);
228 if (likely(!error)) {
229 error = vfs_mkdir(parent_inode, dentry, 0755);
230 up(&parent_inode->i_sem);
232 if (unlikely(error)) {
233 dput(dentry);
234 dentry = NULL;
235 } else {
236 dentry->d_fsdata = info;
239 return dentry;
242 void
243 hwgfs_unregister(
244 hwgfs_handle_t de)
246 struct inode *parent_inode = de->d_parent->d_inode;
248 if (S_ISDIR(de->d_inode->i_mode))
249 vfs_rmdir(parent_inode, de);
250 else
251 vfs_unlink(parent_inode, de);
254 /* XXX: this function is utterly bogus. Every use of it is racy and the
255 prototype is stupid. You have been warned. --hch. */
256 hwgfs_handle_t
257 hwgfs_find_handle(
258 hwgfs_handle_t base,
259 const char *name,
260 unsigned int major, /* IGNORED */
261 unsigned int minor, /* IGNORED */
262 char type, /* IGNORED */
263 int traverse_symlinks)
265 struct dentry *dentry = NULL;
266 struct nameidata nd;
267 int error;
269 BUG_ON(*name=='/');
271 memset(&nd, 0, sizeof(nd));
273 nd.mnt = mntget(hwgfs_vfsmount);
274 nd.dentry = dget(base ? base : hwgfs_vfsmount->mnt_sb->s_root);
275 nd.flags = (traverse_symlinks ? LOOKUP_FOLLOW : 0);
277 error = path_walk(name, &nd);
278 if (likely(!error)) {
279 dentry = nd.dentry;
280 path_release(&nd); /* stale data from here! */
283 return dentry;
286 hwgfs_handle_t
287 hwgfs_get_parent(
288 hwgfs_handle_t de)
290 struct dentry *parent;
292 spin_lock(&de->d_lock);
293 parent = de->d_parent;
294 spin_unlock(&de->d_lock);
296 return parent;
300 hwgfs_set_info(
301 hwgfs_handle_t de,
302 void *info)
304 if (unlikely(de == NULL))
305 return -EINVAL;
306 de->d_fsdata = info;
307 return 0;
310 void *
311 hwgfs_get_info(
312 hwgfs_handle_t de)
314 return de->d_fsdata;
317 EXPORT_SYMBOL(hwgfs_generate_path);
318 EXPORT_SYMBOL(hwgfs_register);
319 EXPORT_SYMBOL(hwgfs_unregister);
320 EXPORT_SYMBOL(hwgfs_mk_symlink);
321 EXPORT_SYMBOL(hwgfs_mk_dir);
322 EXPORT_SYMBOL(hwgfs_find_handle);
323 EXPORT_SYMBOL(hwgfs_get_parent);
324 EXPORT_SYMBOL(hwgfs_set_info);
325 EXPORT_SYMBOL(hwgfs_get_info);