]> git.proxmox.com Git - mirror_spl.git/blame - modules/spl/spl-vnode.c
Add copyin/copyout mapping
[mirror_spl.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
2f5d55aa 162vn_close(vnode_t *vp, int flags, int x1, int x2, void *x3, void *x4)
4b171585 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
2f5d55aa 183vn_remove(const char *path, int seg, int flags)
4b171585 184{
185 struct dentry *dentry;
186 struct nameidata nd;
187 struct inode *inode = NULL;
188 int rc = 0;
189
2f5d55aa 190 BUG_ON(seg != UIO_SYSSPACE);
191 BUG_ON(flags != RMFILE);
192
4b171585 193 rc = path_lookup(path, LOOKUP_PARENT, &nd);
194 if (rc)
195 goto exit;
196
197 rc = -EISDIR;
198 if (nd.last_type != LAST_NORM)
199 goto exit1;
200
201 mutex_lock_nested(&nd.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
202 dentry = lookup_hash(&nd);
203 rc = PTR_ERR(dentry);
204 if (!IS_ERR(dentry)) {
205 /* Why not before? Because we want correct rc value */
206 if (nd.last.name[nd.last.len])
207 goto slashes;
208 inode = dentry->d_inode;
209 if (inode)
210 atomic_inc(&inode->i_count);
211 rc = vfs_unlink(nd.dentry->d_inode, dentry);
212exit2:
213 dput(dentry);
214 }
215 mutex_unlock(&nd.dentry->d_inode->i_mutex);
216 if (inode)
217 iput(inode); /* truncate the inode here */
218exit1:
219 path_release(&nd);
220exit:
221 return rc;
222
223slashes:
224 rc = !dentry->d_inode ? -ENOENT :
225 S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR;
226 goto exit2;
227} /* vn_remove() */
228EXPORT_SYMBOL(vn_remove);
229
230/* Modified do_rename() from linux/fs/namei.c, only uses exported symbols */
231int
232vn_rename(const char *oldname, const char *newname, int x1)
233{
234 struct dentry * old_dir, * new_dir;
235 struct dentry * old_dentry, *new_dentry;
236 struct dentry * trap;
237 struct nameidata oldnd, newnd;
238 int rc = 0;
239
240 rc = path_lookup(oldname, LOOKUP_PARENT, &oldnd);
241 if (rc)
242 goto exit;
243
244 rc = path_lookup(newname, LOOKUP_PARENT, &newnd);
245 if (rc)
246 goto exit1;
247
248 rc = -EXDEV;
249 if (oldnd.mnt != newnd.mnt)
250 goto exit2;
251
252 old_dir = oldnd.dentry;
253 rc = -EBUSY;
254 if (oldnd.last_type != LAST_NORM)
255 goto exit2;
256
257 new_dir = newnd.dentry;
258 if (newnd.last_type != LAST_NORM)
259 goto exit2;
260
261 trap = lock_rename(new_dir, old_dir);
262
263 old_dentry = lookup_hash(&oldnd);
264
265 rc = PTR_ERR(old_dentry);
266 if (IS_ERR(old_dentry))
267 goto exit3;
268
269 /* source must exist */
270 rc = -ENOENT;
271 if (!old_dentry->d_inode)
272 goto exit4;
273
274 /* unless the source is a directory trailing slashes give -ENOTDIR */
275 if (!S_ISDIR(old_dentry->d_inode->i_mode)) {
276 rc = -ENOTDIR;
277 if (oldnd.last.name[oldnd.last.len])
278 goto exit4;
279 if (newnd.last.name[newnd.last.len])
280 goto exit4;
281 }
282
283 /* source should not be ancestor of target */
284 rc = -EINVAL;
285 if (old_dentry == trap)
286 goto exit4;
287
288 new_dentry = lookup_hash(&newnd);
289 rc = PTR_ERR(new_dentry);
290 if (IS_ERR(new_dentry))
291 goto exit4;
292
293 /* target should not be an ancestor of source */
294 rc = -ENOTEMPTY;
295 if (new_dentry == trap)
296 goto exit5;
297
298 rc = vfs_rename(old_dir->d_inode, old_dentry,
299 new_dir->d_inode, new_dentry);
300exit5:
301 dput(new_dentry);
302exit4:
303 dput(old_dentry);
304exit3:
305 unlock_rename(new_dir, old_dir);
306exit2:
307 path_release(&newnd);
308exit1:
309 path_release(&oldnd);
310exit:
311 return rc;
0b3cf046 312}
4b171585 313EXPORT_SYMBOL(vn_rename);
0b3cf046 314
4b171585 315int
316vn_getattr(vnode_t *vp, vattr_t *vap, int flags, int x3, void *x4)
0b3cf046 317{
4b171585 318 struct file *fp;
319 struct kstat stat;
320 int rc;
321
322 BUG_ON(!vp);
323 BUG_ON(!vp->v_fp);
324 BUG_ON(!vap);
325
326 fp = vp->v_fp;
327
328 rc = vfs_getattr(fp->f_vfsmnt, fp->f_dentry, &stat);
329 if (rc)
330 return rc;
331
332 vap->va_type = vn_get_sol_type(stat.mode);
333 vap->va_mode = stat.mode;
334 vap->va_uid = stat.uid;
335 vap->va_gid = stat.gid;
336 vap->va_fsid = 0;
337 vap->va_nodeid = stat.ino;
338 vap->va_nlink = stat.nlink;
339 vap->va_size = stat.size;
340 vap->va_blocksize = stat.blksize;
341 vap->va_atime.tv_sec = stat.atime.tv_sec;
342 vap->va_atime.tv_usec = stat.atime.tv_nsec / NSEC_PER_USEC;
343 vap->va_mtime.tv_sec = stat.mtime.tv_sec;
344 vap->va_mtime.tv_usec = stat.mtime.tv_nsec / NSEC_PER_USEC;
345 vap->va_ctime.tv_sec = stat.ctime.tv_sec;
346 vap->va_ctime.tv_usec = stat.ctime.tv_nsec / NSEC_PER_USEC;
347 vap->va_rdev = stat.rdev;
348 vap->va_blocks = stat.blocks;
349
350 return rc;
0b3cf046 351}
4b171585 352EXPORT_SYMBOL(vn_getattr);
353
2f5d55aa 354int vn_fsync(vnode_t *vp, int flags, void *x3, void *x4)
4b171585 355{
356 BUG_ON(!vp);
357 BUG_ON(!vp->v_fp);
358
359 return file_fsync(vp->v_fp, vp->v_fp->f_dentry, 0);
360} /* vn_fsync() */
361EXPORT_SYMBOL(vn_fsync);