]> bbs.cooldavid.org Git - net-next-2.6.git/blob - fs/xfs/linux-2.6/xfs_iops.c
[XFS] Add an XFS callout to security_inode_init_security; SE Linux is not
[net-next-2.6.git] / fs / xfs / linux-2.6 / xfs_iops.c
1 /*
2  * Copyright (c) 2000-2005 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 #include "xfs.h"
19 #include "xfs_fs.h"
20 #include "xfs_bit.h"
21 #include "xfs_log.h"
22 #include "xfs_inum.h"
23 #include "xfs_trans.h"
24 #include "xfs_sb.h"
25 #include "xfs_ag.h"
26 #include "xfs_dir.h"
27 #include "xfs_dir2.h"
28 #include "xfs_alloc.h"
29 #include "xfs_dmapi.h"
30 #include "xfs_quota.h"
31 #include "xfs_mount.h"
32 #include "xfs_bmap_btree.h"
33 #include "xfs_alloc_btree.h"
34 #include "xfs_ialloc_btree.h"
35 #include "xfs_dir_sf.h"
36 #include "xfs_dir2_sf.h"
37 #include "xfs_attr_sf.h"
38 #include "xfs_dinode.h"
39 #include "xfs_inode.h"
40 #include "xfs_bmap.h"
41 #include "xfs_btree.h"
42 #include "xfs_ialloc.h"
43 #include "xfs_rtalloc.h"
44 #include "xfs_error.h"
45 #include "xfs_itable.h"
46 #include "xfs_rw.h"
47 #include "xfs_acl.h"
48 #include "xfs_cap.h"
49 #include "xfs_mac.h"
50 #include "xfs_attr.h"
51 #include "xfs_buf_item.h"
52 #include "xfs_utils.h"
53
54 #include <linux/xattr.h>
55 #include <linux/namei.h>
56 #include <linux/security.h>
57
58 #define IS_NOATIME(inode) ((inode->i_sb->s_flags & MS_NOATIME) ||       \
59         (S_ISDIR(inode->i_mode) && inode->i_sb->s_flags & MS_NODIRATIME))
60
61 /*
62  * Bring the atime in the XFS inode uptodate.
63  * Used before logging the inode to disk or when the Linux inode goes away.
64  */
65 void
66 xfs_synchronize_atime(
67         xfs_inode_t     *ip)
68 {
69         vnode_t         *vp;
70
71         vp = XFS_ITOV_NULL(ip);
72         if (vp) {
73                 struct inode *inode = &vp->v_inode;
74                 ip->i_d.di_atime.t_sec = (__int32_t)inode->i_atime.tv_sec;
75                 ip->i_d.di_atime.t_nsec = (__int32_t)inode->i_atime.tv_nsec;
76         }
77 }
78
79 /*
80  * Change the requested timestamp in the given inode.
81  * We don't lock across timestamp updates, and we don't log them but
82  * we do record the fact that there is dirty information in core.
83  *
84  * NOTE -- callers MUST combine XFS_ICHGTIME_MOD or XFS_ICHGTIME_CHG
85  *              with XFS_ICHGTIME_ACC to be sure that access time
86  *              update will take.  Calling first with XFS_ICHGTIME_ACC
87  *              and then XFS_ICHGTIME_MOD may fail to modify the access
88  *              timestamp if the filesystem is mounted noacctm.
89  */
90 void
91 xfs_ichgtime(
92         xfs_inode_t     *ip,
93         int             flags)
94 {
95         struct inode    *inode = LINVFS_GET_IP(XFS_ITOV(ip));
96         timespec_t      tv;
97
98         nanotime(&tv);
99         if (flags & XFS_ICHGTIME_MOD) {
100                 inode->i_mtime = tv;
101                 ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec;
102                 ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec;
103         }
104         if (flags & XFS_ICHGTIME_ACC) {
105                 inode->i_atime = tv;
106                 ip->i_d.di_atime.t_sec = (__int32_t)tv.tv_sec;
107                 ip->i_d.di_atime.t_nsec = (__int32_t)tv.tv_nsec;
108         }
109         if (flags & XFS_ICHGTIME_CHG) {
110                 inode->i_ctime = tv;
111                 ip->i_d.di_ctime.t_sec = (__int32_t)tv.tv_sec;
112                 ip->i_d.di_ctime.t_nsec = (__int32_t)tv.tv_nsec;
113         }
114
115         /*
116          * We update the i_update_core field _after_ changing
117          * the timestamps in order to coordinate properly with
118          * xfs_iflush() so that we don't lose timestamp updates.
119          * This keeps us from having to hold the inode lock
120          * while doing this.  We use the SYNCHRONIZE macro to
121          * ensure that the compiler does not reorder the update
122          * of i_update_core above the timestamp updates above.
123          */
124         SYNCHRONIZE();
125         ip->i_update_core = 1;
126         if (!(inode->i_state & I_LOCK))
127                 mark_inode_dirty_sync(inode);
128 }
129
130 /*
131  * Variant on the above which avoids querying the system clock
132  * in situations where we know the Linux inode timestamps have
133  * just been updated (and so we can update our inode cheaply).
134  */
135 void
136 xfs_ichgtime_fast(
137         xfs_inode_t     *ip,
138         struct inode    *inode,
139         int             flags)
140 {
141         timespec_t      *tvp;
142
143         /*
144          * Atime updates for read() & friends are handled lazily now, and
145          * explicit updates must go through xfs_ichgtime()
146          */
147         ASSERT((flags & XFS_ICHGTIME_ACC) == 0);
148
149         /*
150          * We're not supposed to change timestamps in readonly-mounted
151          * filesystems.  Throw it away if anyone asks us.
152          */
153         if (unlikely(IS_RDONLY(inode)))
154                 return;
155
156         if (flags & XFS_ICHGTIME_MOD) {
157                 tvp = &inode->i_mtime;
158                 ip->i_d.di_mtime.t_sec = (__int32_t)tvp->tv_sec;
159                 ip->i_d.di_mtime.t_nsec = (__int32_t)tvp->tv_nsec;
160         }
161         if (flags & XFS_ICHGTIME_CHG) {
162                 tvp = &inode->i_ctime;
163                 ip->i_d.di_ctime.t_sec = (__int32_t)tvp->tv_sec;
164                 ip->i_d.di_ctime.t_nsec = (__int32_t)tvp->tv_nsec;
165         }
166
167         /*
168          * We update the i_update_core field _after_ changing
169          * the timestamps in order to coordinate properly with
170          * xfs_iflush() so that we don't lose timestamp updates.
171          * This keeps us from having to hold the inode lock
172          * while doing this.  We use the SYNCHRONIZE macro to
173          * ensure that the compiler does not reorder the update
174          * of i_update_core above the timestamp updates above.
175          */
176         SYNCHRONIZE();
177         ip->i_update_core = 1;
178         if (!(inode->i_state & I_LOCK))
179                 mark_inode_dirty_sync(inode);
180 }
181
182
183 /*
184  * Pull the link count and size up from the xfs inode to the linux inode
185  */
186 STATIC void
187 validate_fields(
188         struct inode    *ip)
189 {
190         vnode_t         *vp = LINVFS_GET_VP(ip);
191         vattr_t         va;
192         int             error;
193
194         va.va_mask = XFS_AT_NLINK|XFS_AT_SIZE|XFS_AT_NBLOCKS;
195         VOP_GETATTR(vp, &va, ATTR_LAZY, NULL, error);
196         if (likely(!error)) {
197                 ip->i_nlink = va.va_nlink;
198                 ip->i_blocks = va.va_nblocks;
199
200                 /* we're under i_mutex so i_size can't change under us */
201                 if (i_size_read(ip) != va.va_size)
202                         i_size_write(ip, va.va_size);
203         }
204 }
205
206 /*
207  * Hook in SELinux.  This is not quite correct yet, what we really need
208  * here (as we do for default ACLs) is a mechanism by which creation of
209  * these attrs can be journalled at inode creation time (along with the
210  * inode, of course, such that log replay can't cause these to be lost).
211  */
212 STATIC int
213 linvfs_init_security(
214         struct vnode    *vp,
215         struct inode    *dir)
216 {
217         struct inode    *ip = LINVFS_GET_IP(vp);
218         size_t          length;
219         void            *value;
220         char            *name;
221         int             error;
222
223         error = security_inode_init_security(ip, dir, &name, &value, &length);
224         if (error) {
225                 if (error == -EOPNOTSUPP)
226                         return 0;
227                 return -error;
228         }
229
230         VOP_ATTR_SET(vp, name, value, length, ATTR_SECURE, NULL, error);
231         if (!error)
232                 VMODIFY(vp);
233
234         kfree(name);
235         kfree(value);
236         return error;
237 }
238
239 /*
240  * Determine whether a process has a valid fs_struct (kernel daemons
241  * like knfsd don't have an fs_struct).
242  *
243  * XXX(hch):  nfsd is broken, better fix it instead.
244  */
245 STATIC inline int
246 has_fs_struct(struct task_struct *task)
247 {
248         return (task->fs != init_task.fs);
249 }
250
251 STATIC int
252 linvfs_mknod(
253         struct inode    *dir,
254         struct dentry   *dentry,
255         int             mode,
256         dev_t           rdev)
257 {
258         struct inode    *ip;
259         vattr_t         va;
260         vnode_t         *vp = NULL, *dvp = LINVFS_GET_VP(dir);
261         xfs_acl_t       *default_acl = NULL;
262         attrexists_t    test_default_acl = _ACL_DEFAULT_EXISTS;
263         int             error;
264
265         /*
266          * Irix uses Missed'em'V split, but doesn't want to see
267          * the upper 5 bits of (14bit) major.
268          */
269         if (!sysv_valid_dev(rdev) || MAJOR(rdev) & ~0x1ff)
270                 return -EINVAL;
271
272         if (test_default_acl && test_default_acl(dvp)) {
273                 if (!_ACL_ALLOC(default_acl))
274                         return -ENOMEM;
275                 if (!_ACL_GET_DEFAULT(dvp, default_acl)) {
276                         _ACL_FREE(default_acl);
277                         default_acl = NULL;
278                 }
279         }
280
281         if (IS_POSIXACL(dir) && !default_acl && has_fs_struct(current))
282                 mode &= ~current->fs->umask;
283
284         memset(&va, 0, sizeof(va));
285         va.va_mask = XFS_AT_TYPE|XFS_AT_MODE;
286         va.va_mode = mode;
287
288         switch (mode & S_IFMT) {
289         case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK:
290                 va.va_rdev = sysv_encode_dev(rdev);
291                 va.va_mask |= XFS_AT_RDEV;
292                 /*FALLTHROUGH*/
293         case S_IFREG:
294                 VOP_CREATE(dvp, dentry, &va, &vp, NULL, error);
295                 break;
296         case S_IFDIR:
297                 VOP_MKDIR(dvp, dentry, &va, &vp, NULL, error);
298                 break;
299         default:
300                 error = EINVAL;
301                 break;
302         }
303
304         if (!error)
305                 error = linvfs_init_security(vp, dir);
306
307         if (default_acl) {
308                 if (!error) {
309                         error = _ACL_INHERIT(vp, &va, default_acl);
310                         if (!error) {
311                                 VMODIFY(vp);
312                         } else {
313                                 struct dentry   teardown = {};
314                                 int             err2;
315
316                                 /* Oh, the horror.
317                                  * If we can't add the ACL we must back out.
318                                  * ENOSPC can hit here, among other things.
319                                  */
320                                 teardown.d_inode = ip = LINVFS_GET_IP(vp);
321                                 teardown.d_name = dentry->d_name;
322
323                                 vn_mark_bad(vp);
324                                 
325                                 if (S_ISDIR(mode))
326                                         VOP_RMDIR(dvp, &teardown, NULL, err2);
327                                 else
328                                         VOP_REMOVE(dvp, &teardown, NULL, err2);
329                                 VN_RELE(vp);
330                         }
331                 }
332                 _ACL_FREE(default_acl);
333         }
334
335         if (!error) {
336                 ASSERT(vp);
337                 ip = LINVFS_GET_IP(vp);
338
339                 if (S_ISCHR(mode) || S_ISBLK(mode))
340                         ip->i_rdev = rdev;
341                 else if (S_ISDIR(mode))
342                         validate_fields(ip);
343                 d_instantiate(dentry, ip);
344                 validate_fields(dir);
345         }
346         return -error;
347 }
348
349 STATIC int
350 linvfs_create(
351         struct inode    *dir,
352         struct dentry   *dentry,
353         int             mode,
354         struct nameidata *nd)
355 {
356         return linvfs_mknod(dir, dentry, mode, 0);
357 }
358
359 STATIC int
360 linvfs_mkdir(
361         struct inode    *dir,
362         struct dentry   *dentry,
363         int             mode)
364 {
365         return linvfs_mknod(dir, dentry, mode|S_IFDIR, 0);
366 }
367
368 STATIC struct dentry *
369 linvfs_lookup(
370         struct inode    *dir,
371         struct dentry   *dentry,
372         struct nameidata *nd)
373 {
374         struct vnode    *vp = LINVFS_GET_VP(dir), *cvp;
375         int             error;
376
377         if (dentry->d_name.len >= MAXNAMELEN)
378                 return ERR_PTR(-ENAMETOOLONG);
379
380         VOP_LOOKUP(vp, dentry, &cvp, 0, NULL, NULL, error);
381         if (error) {
382                 if (unlikely(error != ENOENT))
383                         return ERR_PTR(-error);
384                 d_add(dentry, NULL);
385                 return NULL;
386         }
387
388         return d_splice_alias(LINVFS_GET_IP(cvp), dentry);
389 }
390
391 STATIC int
392 linvfs_link(
393         struct dentry   *old_dentry,
394         struct inode    *dir,
395         struct dentry   *dentry)
396 {
397         struct inode    *ip;    /* inode of guy being linked to */
398         vnode_t         *tdvp;  /* target directory for new name/link */
399         vnode_t         *vp;    /* vp of name being linked */
400         int             error;
401
402         ip = old_dentry->d_inode;       /* inode being linked to */
403         if (S_ISDIR(ip->i_mode))
404                 return -EPERM;
405
406         tdvp = LINVFS_GET_VP(dir);
407         vp = LINVFS_GET_VP(ip);
408
409         VOP_LINK(tdvp, vp, dentry, NULL, error);
410         if (!error) {
411                 VMODIFY(tdvp);
412                 VN_HOLD(vp);
413                 validate_fields(ip);
414                 d_instantiate(dentry, ip);
415         }
416         return -error;
417 }
418
419 STATIC int
420 linvfs_unlink(
421         struct inode    *dir,
422         struct dentry   *dentry)
423 {
424         struct inode    *inode;
425         vnode_t         *dvp;   /* directory containing name to remove */
426         int             error;
427
428         inode = dentry->d_inode;
429         dvp = LINVFS_GET_VP(dir);
430
431         VOP_REMOVE(dvp, dentry, NULL, error);
432         if (!error) {
433                 validate_fields(dir);   /* For size only */
434                 validate_fields(inode);
435         }
436
437         return -error;
438 }
439
440 STATIC int
441 linvfs_symlink(
442         struct inode    *dir,
443         struct dentry   *dentry,
444         const char      *symname)
445 {
446         struct inode    *ip;
447         vattr_t         va;
448         vnode_t         *dvp;   /* directory containing name of symlink */
449         vnode_t         *cvp;   /* used to lookup symlink to put in dentry */
450         int             error;
451
452         dvp = LINVFS_GET_VP(dir);
453         cvp = NULL;
454
455         memset(&va, 0, sizeof(va));
456         va.va_mode = S_IFLNK |
457                 (irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO);
458         va.va_mask = XFS_AT_TYPE|XFS_AT_MODE;
459
460         error = 0;
461         VOP_SYMLINK(dvp, dentry, &va, (char *)symname, &cvp, NULL, error);
462         if (!error && cvp) {
463                 ip = LINVFS_GET_IP(cvp);
464                 d_instantiate(dentry, ip);
465                 validate_fields(dir);
466                 validate_fields(ip); /* size needs update */
467         }
468         return -error;
469 }
470
471 STATIC int
472 linvfs_rmdir(
473         struct inode    *dir,
474         struct dentry   *dentry)
475 {
476         struct inode    *inode = dentry->d_inode;
477         vnode_t         *dvp = LINVFS_GET_VP(dir);
478         int             error;
479
480         VOP_RMDIR(dvp, dentry, NULL, error);
481         if (!error) {
482                 validate_fields(inode);
483                 validate_fields(dir);
484         }
485         return -error;
486 }
487
488 STATIC int
489 linvfs_rename(
490         struct inode    *odir,
491         struct dentry   *odentry,
492         struct inode    *ndir,
493         struct dentry   *ndentry)
494 {
495         struct inode    *new_inode = ndentry->d_inode;
496         vnode_t         *fvp;   /* from directory */
497         vnode_t         *tvp;   /* target directory */
498         int             error;
499
500         fvp = LINVFS_GET_VP(odir);
501         tvp = LINVFS_GET_VP(ndir);
502
503         VOP_RENAME(fvp, odentry, tvp, ndentry, NULL, error);
504         if (error)
505                 return -error;
506
507         if (new_inode)
508                 validate_fields(new_inode);
509
510         validate_fields(odir);
511         if (ndir != odir)
512                 validate_fields(ndir);
513         return 0;
514 }
515
516 /*
517  * careful here - this function can get called recursively, so
518  * we need to be very careful about how much stack we use.
519  * uio is kmalloced for this reason...
520  */
521 STATIC void *
522 linvfs_follow_link(
523         struct dentry           *dentry,
524         struct nameidata        *nd)
525 {
526         vnode_t                 *vp;
527         uio_t                   *uio;
528         iovec_t                 iov;
529         int                     error;
530         char                    *link;
531
532         ASSERT(dentry);
533         ASSERT(nd);
534
535         link = (char *)kmalloc(MAXNAMELEN+1, GFP_KERNEL);
536         if (!link) {
537                 nd_set_link(nd, ERR_PTR(-ENOMEM));
538                 return NULL;
539         }
540
541         uio = (uio_t *)kmalloc(sizeof(uio_t), GFP_KERNEL);
542         if (!uio) {
543                 kfree(link);
544                 nd_set_link(nd, ERR_PTR(-ENOMEM));
545                 return NULL;
546         }
547
548         vp = LINVFS_GET_VP(dentry->d_inode);
549
550         iov.iov_base = link;
551         iov.iov_len = MAXNAMELEN;
552
553         uio->uio_iov = &iov;
554         uio->uio_offset = 0;
555         uio->uio_segflg = UIO_SYSSPACE;
556         uio->uio_resid = MAXNAMELEN;
557         uio->uio_iovcnt = 1;
558
559         VOP_READLINK(vp, uio, 0, NULL, error);
560         if (error) {
561                 kfree(link);
562                 link = ERR_PTR(-error);
563         } else {
564                 link[MAXNAMELEN - uio->uio_resid] = '\0';
565         }
566         kfree(uio);
567
568         nd_set_link(nd, link);
569         return NULL;
570 }
571
572 STATIC void
573 linvfs_put_link(
574         struct dentry   *dentry,
575         struct nameidata *nd,
576         void            *p)
577 {
578         char            *s = nd_get_link(nd);
579
580         if (!IS_ERR(s))
581                 kfree(s);
582 }
583
584 #ifdef CONFIG_XFS_POSIX_ACL
585 STATIC int
586 linvfs_permission(
587         struct inode    *inode,
588         int             mode,
589         struct nameidata *nd)
590 {
591         vnode_t         *vp = LINVFS_GET_VP(inode);
592         int             error;
593
594         mode <<= 6;             /* convert from linux to vnode access bits */
595         VOP_ACCESS(vp, mode, NULL, error);
596         return -error;
597 }
598 #else
599 #define linvfs_permission NULL
600 #endif
601
602 STATIC int
603 linvfs_getattr(
604         struct vfsmount *mnt,
605         struct dentry   *dentry,
606         struct kstat    *stat)
607 {
608         struct inode    *inode = dentry->d_inode;
609         vnode_t         *vp = LINVFS_GET_VP(inode);
610         int             error = 0;
611
612         if (unlikely(vp->v_flag & VMODIFIED))
613                 error = vn_revalidate(vp);
614         if (!error)
615                 generic_fillattr(inode, stat);
616         return 0;
617 }
618
619 STATIC int
620 linvfs_setattr(
621         struct dentry   *dentry,
622         struct iattr    *attr)
623 {
624         struct inode    *inode = dentry->d_inode;
625         unsigned int    ia_valid = attr->ia_valid;
626         vnode_t         *vp = LINVFS_GET_VP(inode);
627         vattr_t         vattr;
628         int             flags = 0;
629         int             error;
630
631         memset(&vattr, 0, sizeof(vattr_t));
632         if (ia_valid & ATTR_UID) {
633                 vattr.va_mask |= XFS_AT_UID;
634                 vattr.va_uid = attr->ia_uid;
635         }
636         if (ia_valid & ATTR_GID) {
637                 vattr.va_mask |= XFS_AT_GID;
638                 vattr.va_gid = attr->ia_gid;
639         }
640         if (ia_valid & ATTR_SIZE) {
641                 vattr.va_mask |= XFS_AT_SIZE;
642                 vattr.va_size = attr->ia_size;
643         }
644         if (ia_valid & ATTR_ATIME) {
645                 vattr.va_mask |= XFS_AT_ATIME;
646                 vattr.va_atime = attr->ia_atime;
647         }
648         if (ia_valid & ATTR_MTIME) {
649                 vattr.va_mask |= XFS_AT_MTIME;
650                 vattr.va_mtime = attr->ia_mtime;
651         }
652         if (ia_valid & ATTR_CTIME) {
653                 vattr.va_mask |= XFS_AT_CTIME;
654                 vattr.va_ctime = attr->ia_ctime;
655         }
656         if (ia_valid & ATTR_MODE) {
657                 vattr.va_mask |= XFS_AT_MODE;
658                 vattr.va_mode = attr->ia_mode;
659                 if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
660                         inode->i_mode &= ~S_ISGID;
661         }
662
663         if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET))
664                 flags |= ATTR_UTIME;
665 #ifdef ATTR_NO_BLOCK
666         if ((ia_valid & ATTR_NO_BLOCK))
667                 flags |= ATTR_NONBLOCK;
668 #endif
669
670         VOP_SETATTR(vp, &vattr, flags, NULL, error);
671         if (error)
672                 return -error;
673         vn_revalidate(vp);
674         return error;
675 }
676
677 STATIC void
678 linvfs_truncate(
679         struct inode    *inode)
680 {
681         block_truncate_page(inode->i_mapping, inode->i_size, linvfs_get_block);
682 }
683
684 STATIC int
685 linvfs_setxattr(
686         struct dentry   *dentry,
687         const char      *name,
688         const void      *data,
689         size_t          size,
690         int             flags)
691 {
692         vnode_t         *vp = LINVFS_GET_VP(dentry->d_inode);
693         char            *attr = (char *)name;
694         attrnames_t     *namesp;
695         int             xflags = 0;
696         int             error;
697
698         namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT);
699         if (!namesp)
700                 return -EOPNOTSUPP;
701         attr += namesp->attr_namelen;
702         error = namesp->attr_capable(vp, NULL);
703         if (error)
704                 return error;
705
706         /* Convert Linux syscall to XFS internal ATTR flags */
707         if (flags & XATTR_CREATE)
708                 xflags |= ATTR_CREATE;
709         if (flags & XATTR_REPLACE)
710                 xflags |= ATTR_REPLACE;
711         xflags |= namesp->attr_flag;
712         return namesp->attr_set(vp, attr, (void *)data, size, xflags);
713 }
714
715 STATIC ssize_t
716 linvfs_getxattr(
717         struct dentry   *dentry,
718         const char      *name,
719         void            *data,
720         size_t          size)
721 {
722         vnode_t         *vp = LINVFS_GET_VP(dentry->d_inode);
723         char            *attr = (char *)name;
724         attrnames_t     *namesp;
725         int             xflags = 0;
726         ssize_t         error;
727
728         namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT);
729         if (!namesp)
730                 return -EOPNOTSUPP;
731         attr += namesp->attr_namelen;
732         error = namesp->attr_capable(vp, NULL);
733         if (error)
734                 return error;
735
736         /* Convert Linux syscall to XFS internal ATTR flags */
737         if (!size) {
738                 xflags |= ATTR_KERNOVAL;
739                 data = NULL;
740         }
741         xflags |= namesp->attr_flag;
742         return namesp->attr_get(vp, attr, (void *)data, size, xflags);
743 }
744
745 STATIC ssize_t
746 linvfs_listxattr(
747         struct dentry           *dentry,
748         char                    *data,
749         size_t                  size)
750 {
751         vnode_t                 *vp = LINVFS_GET_VP(dentry->d_inode);
752         int                     error, xflags = ATTR_KERNAMELS;
753         ssize_t                 result;
754
755         if (!size)
756                 xflags |= ATTR_KERNOVAL;
757         xflags |= capable(CAP_SYS_ADMIN) ? ATTR_KERNFULLS : ATTR_KERNORMALS;
758
759         error = attr_generic_list(vp, data, size, xflags, &result);
760         if (error < 0)
761                 return error;
762         return result;
763 }
764
765 STATIC int
766 linvfs_removexattr(
767         struct dentry   *dentry,
768         const char      *name)
769 {
770         vnode_t         *vp = LINVFS_GET_VP(dentry->d_inode);
771         char            *attr = (char *)name;
772         attrnames_t     *namesp;
773         int             xflags = 0;
774         int             error;
775
776         namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT);
777         if (!namesp)
778                 return -EOPNOTSUPP;
779         attr += namesp->attr_namelen;
780         error = namesp->attr_capable(vp, NULL);
781         if (error)
782                 return error;
783         xflags |= namesp->attr_flag;
784         return namesp->attr_remove(vp, attr, xflags);
785 }
786
787
788 struct inode_operations linvfs_file_inode_operations = {
789         .permission             = linvfs_permission,
790         .truncate               = linvfs_truncate,
791         .getattr                = linvfs_getattr,
792         .setattr                = linvfs_setattr,
793         .setxattr               = linvfs_setxattr,
794         .getxattr               = linvfs_getxattr,
795         .listxattr              = linvfs_listxattr,
796         .removexattr            = linvfs_removexattr,
797 };
798
799 struct inode_operations linvfs_dir_inode_operations = {
800         .create                 = linvfs_create,
801         .lookup                 = linvfs_lookup,
802         .link                   = linvfs_link,
803         .unlink                 = linvfs_unlink,
804         .symlink                = linvfs_symlink,
805         .mkdir                  = linvfs_mkdir,
806         .rmdir                  = linvfs_rmdir,
807         .mknod                  = linvfs_mknod,
808         .rename                 = linvfs_rename,
809         .permission             = linvfs_permission,
810         .getattr                = linvfs_getattr,
811         .setattr                = linvfs_setattr,
812         .setxattr               = linvfs_setxattr,
813         .getxattr               = linvfs_getxattr,
814         .listxattr              = linvfs_listxattr,
815         .removexattr            = linvfs_removexattr,
816 };
817
818 struct inode_operations linvfs_symlink_inode_operations = {
819         .readlink               = generic_readlink,
820         .follow_link            = linvfs_follow_link,
821         .put_link               = linvfs_put_link,
822         .permission             = linvfs_permission,
823         .getattr                = linvfs_getattr,
824         .setattr                = linvfs_setattr,
825         .setxattr               = linvfs_setxattr,
826         .getxattr               = linvfs_getxattr,
827         .listxattr              = linvfs_listxattr,
828         .removexattr            = linvfs_removexattr,
829 };