diff options
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_iops.c')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_iops.c | 680 |
1 files changed, 680 insertions, 0 deletions
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c new file mode 100644 index 000000000000..407e99359391 --- /dev/null +++ b/fs/xfs/linux-2.6/xfs_iops.c | |||
@@ -0,0 +1,680 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of version 2 of the GNU General Public License as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it would be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
11 | * | ||
12 | * Further, this software is distributed without any warranty that it is | ||
13 | * free of the rightful claim of any third person regarding infringement | ||
14 | * or the like. Any license provided herein, whether implied or | ||
15 | * otherwise, applies only to this software file. Patent licenses, if | ||
16 | * any, provided herein do not apply to combinations of this program with | ||
17 | * other software, or any other product whatsoever. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write the Free Software Foundation, Inc., 59 | ||
21 | * Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
22 | * | ||
23 | * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, | ||
24 | * Mountain View, CA 94043, or: | ||
25 | * | ||
26 | * http://www.sgi.com | ||
27 | * | ||
28 | * For further information regarding this notice, see: | ||
29 | * | ||
30 | * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ | ||
31 | */ | ||
32 | |||
33 | #include "xfs.h" | ||
34 | #include "xfs_fs.h" | ||
35 | #include "xfs_inum.h" | ||
36 | #include "xfs_log.h" | ||
37 | #include "xfs_trans.h" | ||
38 | #include "xfs_sb.h" | ||
39 | #include "xfs_ag.h" | ||
40 | #include "xfs_dir.h" | ||
41 | #include "xfs_dir2.h" | ||
42 | #include "xfs_alloc.h" | ||
43 | #include "xfs_dmapi.h" | ||
44 | #include "xfs_quota.h" | ||
45 | #include "xfs_mount.h" | ||
46 | #include "xfs_alloc_btree.h" | ||
47 | #include "xfs_bmap_btree.h" | ||
48 | #include "xfs_ialloc_btree.h" | ||
49 | #include "xfs_btree.h" | ||
50 | #include "xfs_ialloc.h" | ||
51 | #include "xfs_attr_sf.h" | ||
52 | #include "xfs_dir_sf.h" | ||
53 | #include "xfs_dir2_sf.h" | ||
54 | #include "xfs_dinode.h" | ||
55 | #include "xfs_inode.h" | ||
56 | #include "xfs_bmap.h" | ||
57 | #include "xfs_bit.h" | ||
58 | #include "xfs_rtalloc.h" | ||
59 | #include "xfs_error.h" | ||
60 | #include "xfs_itable.h" | ||
61 | #include "xfs_rw.h" | ||
62 | #include "xfs_acl.h" | ||
63 | #include "xfs_cap.h" | ||
64 | #include "xfs_mac.h" | ||
65 | #include "xfs_attr.h" | ||
66 | #include "xfs_buf_item.h" | ||
67 | #include "xfs_utils.h" | ||
68 | |||
69 | #include <linux/xattr.h> | ||
70 | #include <linux/namei.h> | ||
71 | |||
72 | |||
73 | /* | ||
74 | * Pull the link count and size up from the xfs inode to the linux inode | ||
75 | */ | ||
76 | STATIC void | ||
77 | validate_fields( | ||
78 | struct inode *ip) | ||
79 | { | ||
80 | vnode_t *vp = LINVFS_GET_VP(ip); | ||
81 | vattr_t va; | ||
82 | int error; | ||
83 | |||
84 | va.va_mask = XFS_AT_NLINK|XFS_AT_SIZE|XFS_AT_NBLOCKS; | ||
85 | VOP_GETATTR(vp, &va, ATTR_LAZY, NULL, error); | ||
86 | if (likely(!error)) { | ||
87 | ip->i_nlink = va.va_nlink; | ||
88 | ip->i_blocks = va.va_nblocks; | ||
89 | |||
90 | /* we're under i_sem so i_size can't change under us */ | ||
91 | if (i_size_read(ip) != va.va_size) | ||
92 | i_size_write(ip, va.va_size); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * Determine whether a process has a valid fs_struct (kernel daemons | ||
98 | * like knfsd don't have an fs_struct). | ||
99 | * | ||
100 | * XXX(hch): nfsd is broken, better fix it instead. | ||
101 | */ | ||
102 | STATIC inline int | ||
103 | has_fs_struct(struct task_struct *task) | ||
104 | { | ||
105 | return (task->fs != init_task.fs); | ||
106 | } | ||
107 | |||
108 | STATIC int | ||
109 | linvfs_mknod( | ||
110 | struct inode *dir, | ||
111 | struct dentry *dentry, | ||
112 | int mode, | ||
113 | dev_t rdev) | ||
114 | { | ||
115 | struct inode *ip; | ||
116 | vattr_t va; | ||
117 | vnode_t *vp = NULL, *dvp = LINVFS_GET_VP(dir); | ||
118 | xfs_acl_t *default_acl = NULL; | ||
119 | attrexists_t test_default_acl = _ACL_DEFAULT_EXISTS; | ||
120 | int error; | ||
121 | |||
122 | /* | ||
123 | * Irix uses Missed'em'V split, but doesn't want to see | ||
124 | * the upper 5 bits of (14bit) major. | ||
125 | */ | ||
126 | if (!sysv_valid_dev(rdev) || MAJOR(rdev) & ~0x1ff) | ||
127 | return -EINVAL; | ||
128 | |||
129 | if (test_default_acl && test_default_acl(dvp)) { | ||
130 | if (!_ACL_ALLOC(default_acl)) | ||
131 | return -ENOMEM; | ||
132 | if (!_ACL_GET_DEFAULT(dvp, default_acl)) { | ||
133 | _ACL_FREE(default_acl); | ||
134 | default_acl = NULL; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | if (IS_POSIXACL(dir) && !default_acl && has_fs_struct(current)) | ||
139 | mode &= ~current->fs->umask; | ||
140 | |||
141 | memset(&va, 0, sizeof(va)); | ||
142 | va.va_mask = XFS_AT_TYPE|XFS_AT_MODE; | ||
143 | va.va_type = IFTOVT(mode); | ||
144 | va.va_mode = mode; | ||
145 | |||
146 | switch (mode & S_IFMT) { | ||
147 | case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: | ||
148 | va.va_rdev = sysv_encode_dev(rdev); | ||
149 | va.va_mask |= XFS_AT_RDEV; | ||
150 | /*FALLTHROUGH*/ | ||
151 | case S_IFREG: | ||
152 | VOP_CREATE(dvp, dentry, &va, &vp, NULL, error); | ||
153 | break; | ||
154 | case S_IFDIR: | ||
155 | VOP_MKDIR(dvp, dentry, &va, &vp, NULL, error); | ||
156 | break; | ||
157 | default: | ||
158 | error = EINVAL; | ||
159 | break; | ||
160 | } | ||
161 | |||
162 | if (default_acl) { | ||
163 | if (!error) { | ||
164 | error = _ACL_INHERIT(vp, &va, default_acl); | ||
165 | if (!error) { | ||
166 | VMODIFY(vp); | ||
167 | } else { | ||
168 | struct dentry teardown = {}; | ||
169 | int err2; | ||
170 | |||
171 | /* Oh, the horror. | ||
172 | * If we can't add the ACL we must back out. | ||
173 | * ENOSPC can hit here, among other things. | ||
174 | */ | ||
175 | teardown.d_inode = ip = LINVFS_GET_IP(vp); | ||
176 | teardown.d_name = dentry->d_name; | ||
177 | |||
178 | vn_mark_bad(vp); | ||
179 | |||
180 | if (S_ISDIR(mode)) | ||
181 | VOP_RMDIR(dvp, &teardown, NULL, err2); | ||
182 | else | ||
183 | VOP_REMOVE(dvp, &teardown, NULL, err2); | ||
184 | VN_RELE(vp); | ||
185 | } | ||
186 | } | ||
187 | _ACL_FREE(default_acl); | ||
188 | } | ||
189 | |||
190 | if (!error) { | ||
191 | ASSERT(vp); | ||
192 | ip = LINVFS_GET_IP(vp); | ||
193 | |||
194 | if (S_ISCHR(mode) || S_ISBLK(mode)) | ||
195 | ip->i_rdev = rdev; | ||
196 | else if (S_ISDIR(mode)) | ||
197 | validate_fields(ip); | ||
198 | d_instantiate(dentry, ip); | ||
199 | validate_fields(dir); | ||
200 | } | ||
201 | return -error; | ||
202 | } | ||
203 | |||
204 | STATIC int | ||
205 | linvfs_create( | ||
206 | struct inode *dir, | ||
207 | struct dentry *dentry, | ||
208 | int mode, | ||
209 | struct nameidata *nd) | ||
210 | { | ||
211 | return linvfs_mknod(dir, dentry, mode, 0); | ||
212 | } | ||
213 | |||
214 | STATIC int | ||
215 | linvfs_mkdir( | ||
216 | struct inode *dir, | ||
217 | struct dentry *dentry, | ||
218 | int mode) | ||
219 | { | ||
220 | return linvfs_mknod(dir, dentry, mode|S_IFDIR, 0); | ||
221 | } | ||
222 | |||
223 | STATIC struct dentry * | ||
224 | linvfs_lookup( | ||
225 | struct inode *dir, | ||
226 | struct dentry *dentry, | ||
227 | struct nameidata *nd) | ||
228 | { | ||
229 | struct vnode *vp = LINVFS_GET_VP(dir), *cvp; | ||
230 | int error; | ||
231 | |||
232 | if (dentry->d_name.len >= MAXNAMELEN) | ||
233 | return ERR_PTR(-ENAMETOOLONG); | ||
234 | |||
235 | VOP_LOOKUP(vp, dentry, &cvp, 0, NULL, NULL, error); | ||
236 | if (error) { | ||
237 | if (unlikely(error != ENOENT)) | ||
238 | return ERR_PTR(-error); | ||
239 | d_add(dentry, NULL); | ||
240 | return NULL; | ||
241 | } | ||
242 | |||
243 | return d_splice_alias(LINVFS_GET_IP(cvp), dentry); | ||
244 | } | ||
245 | |||
246 | STATIC int | ||
247 | linvfs_link( | ||
248 | struct dentry *old_dentry, | ||
249 | struct inode *dir, | ||
250 | struct dentry *dentry) | ||
251 | { | ||
252 | struct inode *ip; /* inode of guy being linked to */ | ||
253 | vnode_t *tdvp; /* target directory for new name/link */ | ||
254 | vnode_t *vp; /* vp of name being linked */ | ||
255 | int error; | ||
256 | |||
257 | ip = old_dentry->d_inode; /* inode being linked to */ | ||
258 | if (S_ISDIR(ip->i_mode)) | ||
259 | return -EPERM; | ||
260 | |||
261 | tdvp = LINVFS_GET_VP(dir); | ||
262 | vp = LINVFS_GET_VP(ip); | ||
263 | |||
264 | VOP_LINK(tdvp, vp, dentry, NULL, error); | ||
265 | if (!error) { | ||
266 | VMODIFY(tdvp); | ||
267 | VN_HOLD(vp); | ||
268 | validate_fields(ip); | ||
269 | d_instantiate(dentry, ip); | ||
270 | } | ||
271 | return -error; | ||
272 | } | ||
273 | |||
274 | STATIC int | ||
275 | linvfs_unlink( | ||
276 | struct inode *dir, | ||
277 | struct dentry *dentry) | ||
278 | { | ||
279 | struct inode *inode; | ||
280 | vnode_t *dvp; /* directory containing name to remove */ | ||
281 | int error; | ||
282 | |||
283 | inode = dentry->d_inode; | ||
284 | dvp = LINVFS_GET_VP(dir); | ||
285 | |||
286 | VOP_REMOVE(dvp, dentry, NULL, error); | ||
287 | if (!error) { | ||
288 | validate_fields(dir); /* For size only */ | ||
289 | validate_fields(inode); | ||
290 | } | ||
291 | |||
292 | return -error; | ||
293 | } | ||
294 | |||
295 | STATIC int | ||
296 | linvfs_symlink( | ||
297 | struct inode *dir, | ||
298 | struct dentry *dentry, | ||
299 | const char *symname) | ||
300 | { | ||
301 | struct inode *ip; | ||
302 | vattr_t va; | ||
303 | vnode_t *dvp; /* directory containing name of symlink */ | ||
304 | vnode_t *cvp; /* used to lookup symlink to put in dentry */ | ||
305 | int error; | ||
306 | |||
307 | dvp = LINVFS_GET_VP(dir); | ||
308 | cvp = NULL; | ||
309 | |||
310 | memset(&va, 0, sizeof(va)); | ||
311 | va.va_type = VLNK; | ||
312 | va.va_mode = irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO; | ||
313 | va.va_mask = XFS_AT_TYPE|XFS_AT_MODE; | ||
314 | |||
315 | error = 0; | ||
316 | VOP_SYMLINK(dvp, dentry, &va, (char *)symname, &cvp, NULL, error); | ||
317 | if (!error && cvp) { | ||
318 | ASSERT(cvp->v_type == VLNK); | ||
319 | ip = LINVFS_GET_IP(cvp); | ||
320 | d_instantiate(dentry, ip); | ||
321 | validate_fields(dir); | ||
322 | validate_fields(ip); /* size needs update */ | ||
323 | } | ||
324 | return -error; | ||
325 | } | ||
326 | |||
327 | STATIC int | ||
328 | linvfs_rmdir( | ||
329 | struct inode *dir, | ||
330 | struct dentry *dentry) | ||
331 | { | ||
332 | struct inode *inode = dentry->d_inode; | ||
333 | vnode_t *dvp = LINVFS_GET_VP(dir); | ||
334 | int error; | ||
335 | |||
336 | VOP_RMDIR(dvp, dentry, NULL, error); | ||
337 | if (!error) { | ||
338 | validate_fields(inode); | ||
339 | validate_fields(dir); | ||
340 | } | ||
341 | return -error; | ||
342 | } | ||
343 | |||
344 | STATIC int | ||
345 | linvfs_rename( | ||
346 | struct inode *odir, | ||
347 | struct dentry *odentry, | ||
348 | struct inode *ndir, | ||
349 | struct dentry *ndentry) | ||
350 | { | ||
351 | struct inode *new_inode = ndentry->d_inode; | ||
352 | vnode_t *fvp; /* from directory */ | ||
353 | vnode_t *tvp; /* target directory */ | ||
354 | int error; | ||
355 | |||
356 | fvp = LINVFS_GET_VP(odir); | ||
357 | tvp = LINVFS_GET_VP(ndir); | ||
358 | |||
359 | VOP_RENAME(fvp, odentry, tvp, ndentry, NULL, error); | ||
360 | if (error) | ||
361 | return -error; | ||
362 | |||
363 | if (new_inode) | ||
364 | validate_fields(new_inode); | ||
365 | |||
366 | validate_fields(odir); | ||
367 | if (ndir != odir) | ||
368 | validate_fields(ndir); | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | /* | ||
373 | * careful here - this function can get called recursively, so | ||
374 | * we need to be very careful about how much stack we use. | ||
375 | * uio is kmalloced for this reason... | ||
376 | */ | ||
377 | STATIC int | ||
378 | linvfs_follow_link( | ||
379 | struct dentry *dentry, | ||
380 | struct nameidata *nd) | ||
381 | { | ||
382 | vnode_t *vp; | ||
383 | uio_t *uio; | ||
384 | iovec_t iov; | ||
385 | int error; | ||
386 | char *link; | ||
387 | |||
388 | ASSERT(dentry); | ||
389 | ASSERT(nd); | ||
390 | |||
391 | link = (char *)kmalloc(MAXNAMELEN+1, GFP_KERNEL); | ||
392 | if (!link) { | ||
393 | nd_set_link(nd, ERR_PTR(-ENOMEM)); | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | uio = (uio_t *)kmalloc(sizeof(uio_t), GFP_KERNEL); | ||
398 | if (!uio) { | ||
399 | kfree(link); | ||
400 | nd_set_link(nd, ERR_PTR(-ENOMEM)); | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | vp = LINVFS_GET_VP(dentry->d_inode); | ||
405 | |||
406 | iov.iov_base = link; | ||
407 | iov.iov_len = MAXNAMELEN; | ||
408 | |||
409 | uio->uio_iov = &iov; | ||
410 | uio->uio_offset = 0; | ||
411 | uio->uio_segflg = UIO_SYSSPACE; | ||
412 | uio->uio_resid = MAXNAMELEN; | ||
413 | uio->uio_iovcnt = 1; | ||
414 | |||
415 | VOP_READLINK(vp, uio, 0, NULL, error); | ||
416 | if (error) { | ||
417 | kfree(link); | ||
418 | link = ERR_PTR(-error); | ||
419 | } else { | ||
420 | link[MAXNAMELEN - uio->uio_resid] = '\0'; | ||
421 | } | ||
422 | kfree(uio); | ||
423 | |||
424 | nd_set_link(nd, link); | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | static void linvfs_put_link(struct dentry *dentry, struct nameidata *nd) | ||
429 | { | ||
430 | char *s = nd_get_link(nd); | ||
431 | if (!IS_ERR(s)) | ||
432 | kfree(s); | ||
433 | } | ||
434 | |||
435 | #ifdef CONFIG_XFS_POSIX_ACL | ||
436 | STATIC int | ||
437 | linvfs_permission( | ||
438 | struct inode *inode, | ||
439 | int mode, | ||
440 | struct nameidata *nd) | ||
441 | { | ||
442 | vnode_t *vp = LINVFS_GET_VP(inode); | ||
443 | int error; | ||
444 | |||
445 | mode <<= 6; /* convert from linux to vnode access bits */ | ||
446 | VOP_ACCESS(vp, mode, NULL, error); | ||
447 | return -error; | ||
448 | } | ||
449 | #else | ||
450 | #define linvfs_permission NULL | ||
451 | #endif | ||
452 | |||
453 | STATIC int | ||
454 | linvfs_getattr( | ||
455 | struct vfsmount *mnt, | ||
456 | struct dentry *dentry, | ||
457 | struct kstat *stat) | ||
458 | { | ||
459 | struct inode *inode = dentry->d_inode; | ||
460 | vnode_t *vp = LINVFS_GET_VP(inode); | ||
461 | int error = 0; | ||
462 | |||
463 | if (unlikely(vp->v_flag & VMODIFIED)) | ||
464 | error = vn_revalidate(vp); | ||
465 | if (!error) | ||
466 | generic_fillattr(inode, stat); | ||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | STATIC int | ||
471 | linvfs_setattr( | ||
472 | struct dentry *dentry, | ||
473 | struct iattr *attr) | ||
474 | { | ||
475 | struct inode *inode = dentry->d_inode; | ||
476 | unsigned int ia_valid = attr->ia_valid; | ||
477 | vnode_t *vp = LINVFS_GET_VP(inode); | ||
478 | vattr_t vattr; | ||
479 | int flags = 0; | ||
480 | int error; | ||
481 | |||
482 | memset(&vattr, 0, sizeof(vattr_t)); | ||
483 | if (ia_valid & ATTR_UID) { | ||
484 | vattr.va_mask |= XFS_AT_UID; | ||
485 | vattr.va_uid = attr->ia_uid; | ||
486 | } | ||
487 | if (ia_valid & ATTR_GID) { | ||
488 | vattr.va_mask |= XFS_AT_GID; | ||
489 | vattr.va_gid = attr->ia_gid; | ||
490 | } | ||
491 | if (ia_valid & ATTR_SIZE) { | ||
492 | vattr.va_mask |= XFS_AT_SIZE; | ||
493 | vattr.va_size = attr->ia_size; | ||
494 | } | ||
495 | if (ia_valid & ATTR_ATIME) { | ||
496 | vattr.va_mask |= XFS_AT_ATIME; | ||
497 | vattr.va_atime = attr->ia_atime; | ||
498 | } | ||
499 | if (ia_valid & ATTR_MTIME) { | ||
500 | vattr.va_mask |= XFS_AT_MTIME; | ||
501 | vattr.va_mtime = attr->ia_mtime; | ||
502 | } | ||
503 | if (ia_valid & ATTR_CTIME) { | ||
504 | vattr.va_mask |= XFS_AT_CTIME; | ||
505 | vattr.va_ctime = attr->ia_ctime; | ||
506 | } | ||
507 | if (ia_valid & ATTR_MODE) { | ||
508 | vattr.va_mask |= XFS_AT_MODE; | ||
509 | vattr.va_mode = attr->ia_mode; | ||
510 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) | ||
511 | inode->i_mode &= ~S_ISGID; | ||
512 | } | ||
513 | |||
514 | if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) | ||
515 | flags |= ATTR_UTIME; | ||
516 | #ifdef ATTR_NO_BLOCK | ||
517 | if ((ia_valid & ATTR_NO_BLOCK)) | ||
518 | flags |= ATTR_NONBLOCK; | ||
519 | #endif | ||
520 | |||
521 | VOP_SETATTR(vp, &vattr, flags, NULL, error); | ||
522 | if (error) | ||
523 | return -error; | ||
524 | vn_revalidate(vp); | ||
525 | return error; | ||
526 | } | ||
527 | |||
528 | STATIC void | ||
529 | linvfs_truncate( | ||
530 | struct inode *inode) | ||
531 | { | ||
532 | block_truncate_page(inode->i_mapping, inode->i_size, linvfs_get_block); | ||
533 | } | ||
534 | |||
535 | STATIC int | ||
536 | linvfs_setxattr( | ||
537 | struct dentry *dentry, | ||
538 | const char *name, | ||
539 | const void *data, | ||
540 | size_t size, | ||
541 | int flags) | ||
542 | { | ||
543 | vnode_t *vp = LINVFS_GET_VP(dentry->d_inode); | ||
544 | char *attr = (char *)name; | ||
545 | attrnames_t *namesp; | ||
546 | int xflags = 0; | ||
547 | int error; | ||
548 | |||
549 | namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT); | ||
550 | if (!namesp) | ||
551 | return -EOPNOTSUPP; | ||
552 | attr += namesp->attr_namelen; | ||
553 | error = namesp->attr_capable(vp, NULL); | ||
554 | if (error) | ||
555 | return error; | ||
556 | |||
557 | /* Convert Linux syscall to XFS internal ATTR flags */ | ||
558 | if (flags & XATTR_CREATE) | ||
559 | xflags |= ATTR_CREATE; | ||
560 | if (flags & XATTR_REPLACE) | ||
561 | xflags |= ATTR_REPLACE; | ||
562 | xflags |= namesp->attr_flag; | ||
563 | return namesp->attr_set(vp, attr, (void *)data, size, xflags); | ||
564 | } | ||
565 | |||
566 | STATIC ssize_t | ||
567 | linvfs_getxattr( | ||
568 | struct dentry *dentry, | ||
569 | const char *name, | ||
570 | void *data, | ||
571 | size_t size) | ||
572 | { | ||
573 | vnode_t *vp = LINVFS_GET_VP(dentry->d_inode); | ||
574 | char *attr = (char *)name; | ||
575 | attrnames_t *namesp; | ||
576 | int xflags = 0; | ||
577 | ssize_t error; | ||
578 | |||
579 | namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT); | ||
580 | if (!namesp) | ||
581 | return -EOPNOTSUPP; | ||
582 | attr += namesp->attr_namelen; | ||
583 | error = namesp->attr_capable(vp, NULL); | ||
584 | if (error) | ||
585 | return error; | ||
586 | |||
587 | /* Convert Linux syscall to XFS internal ATTR flags */ | ||
588 | if (!size) { | ||
589 | xflags |= ATTR_KERNOVAL; | ||
590 | data = NULL; | ||
591 | } | ||
592 | xflags |= namesp->attr_flag; | ||
593 | return namesp->attr_get(vp, attr, (void *)data, size, xflags); | ||
594 | } | ||
595 | |||
596 | STATIC ssize_t | ||
597 | linvfs_listxattr( | ||
598 | struct dentry *dentry, | ||
599 | char *data, | ||
600 | size_t size) | ||
601 | { | ||
602 | vnode_t *vp = LINVFS_GET_VP(dentry->d_inode); | ||
603 | int error, xflags = ATTR_KERNAMELS; | ||
604 | ssize_t result; | ||
605 | |||
606 | if (!size) | ||
607 | xflags |= ATTR_KERNOVAL; | ||
608 | xflags |= capable(CAP_SYS_ADMIN) ? ATTR_KERNFULLS : ATTR_KERNORMALS; | ||
609 | |||
610 | error = attr_generic_list(vp, data, size, xflags, &result); | ||
611 | if (error < 0) | ||
612 | return error; | ||
613 | return result; | ||
614 | } | ||
615 | |||
616 | STATIC int | ||
617 | linvfs_removexattr( | ||
618 | struct dentry *dentry, | ||
619 | const char *name) | ||
620 | { | ||
621 | vnode_t *vp = LINVFS_GET_VP(dentry->d_inode); | ||
622 | char *attr = (char *)name; | ||
623 | attrnames_t *namesp; | ||
624 | int xflags = 0; | ||
625 | int error; | ||
626 | |||
627 | namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT); | ||
628 | if (!namesp) | ||
629 | return -EOPNOTSUPP; | ||
630 | attr += namesp->attr_namelen; | ||
631 | error = namesp->attr_capable(vp, NULL); | ||
632 | if (error) | ||
633 | return error; | ||
634 | xflags |= namesp->attr_flag; | ||
635 | return namesp->attr_remove(vp, attr, xflags); | ||
636 | } | ||
637 | |||
638 | |||
639 | struct inode_operations linvfs_file_inode_operations = { | ||
640 | .permission = linvfs_permission, | ||
641 | .truncate = linvfs_truncate, | ||
642 | .getattr = linvfs_getattr, | ||
643 | .setattr = linvfs_setattr, | ||
644 | .setxattr = linvfs_setxattr, | ||
645 | .getxattr = linvfs_getxattr, | ||
646 | .listxattr = linvfs_listxattr, | ||
647 | .removexattr = linvfs_removexattr, | ||
648 | }; | ||
649 | |||
650 | struct inode_operations linvfs_dir_inode_operations = { | ||
651 | .create = linvfs_create, | ||
652 | .lookup = linvfs_lookup, | ||
653 | .link = linvfs_link, | ||
654 | .unlink = linvfs_unlink, | ||
655 | .symlink = linvfs_symlink, | ||
656 | .mkdir = linvfs_mkdir, | ||
657 | .rmdir = linvfs_rmdir, | ||
658 | .mknod = linvfs_mknod, | ||
659 | .rename = linvfs_rename, | ||
660 | .permission = linvfs_permission, | ||
661 | .getattr = linvfs_getattr, | ||
662 | .setattr = linvfs_setattr, | ||
663 | .setxattr = linvfs_setxattr, | ||
664 | .getxattr = linvfs_getxattr, | ||
665 | .listxattr = linvfs_listxattr, | ||
666 | .removexattr = linvfs_removexattr, | ||
667 | }; | ||
668 | |||
669 | struct inode_operations linvfs_symlink_inode_operations = { | ||
670 | .readlink = generic_readlink, | ||
671 | .follow_link = linvfs_follow_link, | ||
672 | .put_link = linvfs_put_link, | ||
673 | .permission = linvfs_permission, | ||
674 | .getattr = linvfs_getattr, | ||
675 | .setattr = linvfs_setattr, | ||
676 | .setxattr = linvfs_setxattr, | ||
677 | .getxattr = linvfs_getxattr, | ||
678 | .listxattr = linvfs_listxattr, | ||
679 | .removexattr = linvfs_removexattr, | ||
680 | }; | ||