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