]> git.proxmox.com Git - mirror_spl-debian.git/blame - modules/spl/spl-vnode.c
- Implemented vnode interfaces and 6 test cases to the test suite.
[mirror_spl-debian.git] / modules / spl / spl-vnode.c
CommitLineData
0b3cf046 1#include <sys/sysmacros.h>
4b171585 2#include <sys/vnode.h>
0b3cf046 3#include "config.h"
4
4b171585 5void *rootdir = NULL;
6EXPORT_SYMBOL(rootdir);
7
8static vtype_t
9vn_get_sol_type(umode_t mode)
10{
11 if (S_ISREG(mode))
12 return VREG;
13
14 if (S_ISDIR(mode))
15 return VDIR;
16
17 if (S_ISCHR(mode))
18 return VCHR;
19
20 if (S_ISBLK(mode))
21 return VBLK;
22
23 if (S_ISFIFO(mode))
24 return VFIFO;
25
26 if (S_ISLNK(mode))
27 return VLNK;
28
29 if (S_ISSOCK(mode))
30 return VSOCK;
31
32 if (S_ISCHR(mode))
33 return VCHR;
34
35 return VNON;
36} /* vn_get_sol_type() */
37
0b3cf046 38int
4b171585 39vn_open(const char *path, int seg, int flags, int mode,
40 vnode_t **vpp, int x1, void *x2)
0b3cf046 41{
4b171585 42 struct file *fp;
43 struct kstat stat;
44 int rc, saved_umask, flags_rw;
0b3cf046 45 vnode_t *vp;
0b3cf046 46
4b171585 47 BUG_ON(seg != UIO_SYSSPACE);
48 BUG_ON(!vpp);
49 *vpp = NULL;
50
51 if (!(flags & FCREAT) && (flags & FWRITE))
52 flags |= FEXCL;
53
54 flags_rw = flags & (FWRITE | FREAD);
55 flags &= ~(FWRITE | FREAD);
56 switch (flags_rw) {
57 case FWRITE: flags |= O_WRONLY;
58 case FREAD: flags |= O_RDONLY;
59 case (FWRITE | FREAD): flags |= O_RDWR;
0b3cf046 60 }
0b3cf046 61
62 if (flags & FCREAT)
4b171585 63 saved_umask = xchg(&current->fs->umask, 0);
0b3cf046 64
4b171585 65 fp = filp_open(path, flags, mode);
0b3cf046 66
67 if (flags & FCREAT)
4b171585 68 (void)xchg(&current->fs->umask, saved_umask);
0b3cf046 69
4b171585 70 if (IS_ERR(fp))
71 return PTR_ERR(fp);
0b3cf046 72
4b171585 73 rc = vfs_getattr(fp->f_vfsmnt, fp->f_dentry, &stat);
74 if (rc) {
75 filp_close(fp, 0);
76 return rc;
0b3cf046 77 }
78
4b171585 79 vp = kmalloc(sizeof(vnode_t), GFP_ATOMIC);
80 if (!vp) {
81 filp_close(fp, 0);
82 return -ENOMEM;
83 }
0b3cf046 84
4b171585 85 vp->v_type = vn_get_sol_type(stat.mode);
86 vp->v_fp = fp;
87 *vpp = vp;
0b3cf046 88
4b171585 89 return 0;
90} /* vn_open() */
91EXPORT_SYMBOL(vn_open);
0b3cf046 92
0b3cf046 93int
4b171585 94vn_openat(const char *path, int seg, int flags, int mode,
95 vnode_t **vpp, int x1, void *x2, vnode_t *vp, int fd)
0b3cf046 96{
4b171585 97 char *realpath;
98 int rc;
0b3cf046 99
4b171585 100 BUG_ON(vp != rootdir);
0b3cf046 101
4b171585 102 realpath = kmalloc(strlen(path) + 2, GFP_KERNEL);
103 if (!realpath)
104 return -ENOMEM;
0b3cf046 105
4b171585 106 sprintf(realpath, "/%s", path);
107 rc = vn_open(realpath, seg, flags, mode, vpp, x1, x2);
0b3cf046 108
4b171585 109 kfree(realpath);
110
111 return rc;
112} /* vn_openat() */
113EXPORT_SYMBOL(vn_openat);
0b3cf046 114
0b3cf046 115int
4b171585 116vn_rdwr(uio_rw_t uio, vnode_t *vp, void *addr, ssize_t len, offset_t off,
117 int seg, int x1, rlim64_t x2, void *x3, ssize_t *residp)
0b3cf046 118{
4b171585 119 loff_t offset;
120 mm_segment_t saved_fs;
121 struct file *fp;
122 int rc;
123
124 BUG_ON(!(uio == UIO_WRITE || uio == UIO_READ));
125 BUG_ON(!vp);
126 BUG_ON(!vp->v_fp);
127 BUG_ON(seg != UIO_SYSSPACE);
128 BUG_ON(x1 != 0);
129 BUG_ON(x2 != RLIM64_INFINITY);
130
131 offset = off;
132 fp = vp->v_fp;
133
134 /* Writable user data segment must be briefly increased for this
135 * process so we can use the user space read call paths to write
136 * in to memory allocated by the kernel. */
137 saved_fs = get_fs();
138 set_fs(get_ds());
139
140 if (uio & UIO_WRITE)
141 rc = vfs_write(fp, addr, len, &offset);
142 else
143 rc = vfs_read(fp, addr, len, &offset);
144
145 set_fs(saved_fs);
146
147 if (rc < 0)
148 return rc;
0b3cf046 149
4b171585 150 if (residp) {
151 *residp = len - rc;
0b3cf046 152 } else {
4b171585 153 if (rc != len)
154 return -EIO;
0b3cf046 155 }
156
4b171585 157 return 0;
158} /* vn_rdwr() */
159EXPORT_SYMBOL(vn_rdwr);
160
161int
162vn_close(vnode_t *vp, int flags, int x1, int x2, int x3, int x4)
163{
164 int rc;
165
166 BUG_ON(!vp);
167 BUG_ON(!vp->v_fp);
168
169 rc = filp_close(vp->v_fp, 0);
170 kfree(vp);
171
172 return rc;
173} /* vn_close() */
174EXPORT_SYMBOL(vn_close);
175
176static struct dentry *lookup_hash(struct nameidata *nd)
177{
178 return __lookup_hash(&nd->last, nd->dentry, nd);
179} /* lookup_hash() */
180
181/* Modified do_unlinkat() from linux/fs/namei.c, only uses exported symbols */
182int
183vn_remove(const char *path, int x1, int x2)
184{
185 struct dentry *dentry;
186 struct nameidata nd;
187 struct inode *inode = NULL;
188 int rc = 0;
189
190 rc = path_lookup(path, LOOKUP_PARENT, &nd);
191 if (rc)
192 goto exit;
193
194 rc = -EISDIR;
195 if (nd.last_type != LAST_NORM)
196 goto exit1;
197
198 mutex_lock_nested(&nd.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
199 dentry = lookup_hash(&nd);
200 rc = PTR_ERR(dentry);
201 if (!IS_ERR(dentry)) {
202 /* Why not before? Because we want correct rc value */
203 if (nd.last.name[nd.last.len])
204 goto slashes;
205 inode = dentry->d_inode;
206 if (inode)
207 atomic_inc(&inode->i_count);
208 rc = vfs_unlink(nd.dentry->d_inode, dentry);
209exit2:
210 dput(dentry);
211 }
212 mutex_unlock(&nd.dentry->d_inode->i_mutex);
213 if (inode)
214 iput(inode); /* truncate the inode here */
215exit1:
216 path_release(&nd);
217exit:
218 return rc;
219
220slashes:
221 rc = !dentry->d_inode ? -ENOENT :
222 S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR;
223 goto exit2;
224} /* vn_remove() */
225EXPORT_SYMBOL(vn_remove);
226
227/* Modified do_rename() from linux/fs/namei.c, only uses exported symbols */
228int
229vn_rename(const char *oldname, const char *newname, int x1)
230{
231 struct dentry * old_dir, * new_dir;
232 struct dentry * old_dentry, *new_dentry;
233 struct dentry * trap;
234 struct nameidata oldnd, newnd;
235 int rc = 0;
236
237 rc = path_lookup(oldname, LOOKUP_PARENT, &oldnd);
238 if (rc)
239 goto exit;
240
241 rc = path_lookup(newname, LOOKUP_PARENT, &newnd);
242 if (rc)
243 goto exit1;
244
245 rc = -EXDEV;
246 if (oldnd.mnt != newnd.mnt)
247 goto exit2;
248
249 old_dir = oldnd.dentry;
250 rc = -EBUSY;
251 if (oldnd.last_type != LAST_NORM)
252 goto exit2;
253
254 new_dir = newnd.dentry;
255 if (newnd.last_type != LAST_NORM)
256 goto exit2;
257
258 trap = lock_rename(new_dir, old_dir);
259
260 old_dentry = lookup_hash(&oldnd);
261
262 rc = PTR_ERR(old_dentry);
263 if (IS_ERR(old_dentry))
264 goto exit3;
265
266 /* source must exist */
267 rc = -ENOENT;
268 if (!old_dentry->d_inode)
269 goto exit4;
270
271 /* unless the source is a directory trailing slashes give -ENOTDIR */
272 if (!S_ISDIR(old_dentry->d_inode->i_mode)) {
273 rc = -ENOTDIR;
274 if (oldnd.last.name[oldnd.last.len])
275 goto exit4;
276 if (newnd.last.name[newnd.last.len])
277 goto exit4;
278 }
279
280 /* source should not be ancestor of target */
281 rc = -EINVAL;
282 if (old_dentry == trap)
283 goto exit4;
284
285 new_dentry = lookup_hash(&newnd);
286 rc = PTR_ERR(new_dentry);
287 if (IS_ERR(new_dentry))
288 goto exit4;
289
290 /* target should not be an ancestor of source */
291 rc = -ENOTEMPTY;
292 if (new_dentry == trap)
293 goto exit5;
294
295 rc = vfs_rename(old_dir->d_inode, old_dentry,
296 new_dir->d_inode, new_dentry);
297exit5:
298 dput(new_dentry);
299exit4:
300 dput(old_dentry);
301exit3:
302 unlock_rename(new_dir, old_dir);
303exit2:
304 path_release(&newnd);
305exit1:
306 path_release(&oldnd);
307exit:
308 return rc;
0b3cf046 309}
4b171585 310EXPORT_SYMBOL(vn_rename);
0b3cf046 311
4b171585 312int
313vn_getattr(vnode_t *vp, vattr_t *vap, int flags, int x3, void *x4)
0b3cf046 314{
4b171585 315 struct file *fp;
316 struct kstat stat;
317 int rc;
318
319 BUG_ON(!vp);
320 BUG_ON(!vp->v_fp);
321 BUG_ON(!vap);
322
323 fp = vp->v_fp;
324
325 rc = vfs_getattr(fp->f_vfsmnt, fp->f_dentry, &stat);
326 if (rc)
327 return rc;
328
329 vap->va_type = vn_get_sol_type(stat.mode);
330 vap->va_mode = stat.mode;
331 vap->va_uid = stat.uid;
332 vap->va_gid = stat.gid;
333 vap->va_fsid = 0;
334 vap->va_nodeid = stat.ino;
335 vap->va_nlink = stat.nlink;
336 vap->va_size = stat.size;
337 vap->va_blocksize = stat.blksize;
338 vap->va_atime.tv_sec = stat.atime.tv_sec;
339 vap->va_atime.tv_usec = stat.atime.tv_nsec / NSEC_PER_USEC;
340 vap->va_mtime.tv_sec = stat.mtime.tv_sec;
341 vap->va_mtime.tv_usec = stat.mtime.tv_nsec / NSEC_PER_USEC;
342 vap->va_ctime.tv_sec = stat.ctime.tv_sec;
343 vap->va_ctime.tv_usec = stat.ctime.tv_nsec / NSEC_PER_USEC;
344 vap->va_rdev = stat.rdev;
345 vap->va_blocks = stat.blocks;
346
347 return rc;
0b3cf046 348}
4b171585 349EXPORT_SYMBOL(vn_getattr);
350
351int vn_fsync(vnode_t *vp, int flags, int x3, int x4)
352{
353 BUG_ON(!vp);
354 BUG_ON(!vp->v_fp);
355
356 return file_fsync(vp->v_fp, vp->v_fp->f_dentry, 0);
357} /* vn_fsync() */
358EXPORT_SYMBOL(vn_fsync);