blob: d388d14efe3e6b0e49f5444619ddbee809731c30 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Nathan Scott7b718762005-11-02 14:58:39 +11002 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
Nathan Scott7b718762005-11-02 14:58:39 +11005 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * published by the Free Software Foundation.
8 *
Nathan Scott7b718762005-11-02 14:58:39 +11009 * 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.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
Nathan Scott7b718762005-11-02 14:58:39 +110014 * 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include "xfs.h"
19#include "xfs_fs.h"
Nathan Scotta844f452005-11-02 14:38:42 +110020#include "xfs_bit.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include "xfs_log.h"
Nathan Scotta844f452005-11-02 14:38:42 +110022#include "xfs_inum.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#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"
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "xfs_bmap_btree.h"
Nathan Scotta844f452005-11-02 14:38:42 +110033#include "xfs_alloc_btree.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include "xfs_ialloc_btree.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include "xfs_dir_sf.h"
36#include "xfs_dir2_sf.h"
Nathan Scotta844f452005-11-02 14:38:42 +110037#include "xfs_attr_sf.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include "xfs_dinode.h"
39#include "xfs_inode.h"
40#include "xfs_bmap.h"
Nathan Scotta844f452005-11-02 14:38:42 +110041#include "xfs_btree.h"
42#include "xfs_ialloc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#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>
Nathan Scott446ada42006-01-11 15:35:44 +110056#include <linux/security.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Christoph Hellwigfc33a7b2006-01-09 20:52:17 -080058#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
Nathan Scott4aeb6642005-11-02 11:43:58 +110061/*
Christoph Hellwig75e17b32006-01-11 20:58:44 +110062 * Get a XFS inode from a given vnode.
63 */
64xfs_inode_t *
65xfs_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/*
Christoph Hellwig42fe2b12006-01-11 15:35:17 +110078 * Bring the atime in the XFS inode uptodate.
79 * Used before logging the inode to disk or when the Linux inode goes away.
80 */
81void
82xfs_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/*
Nathan Scott4aeb6642005-11-02 11:43:58 +110096 * 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 */
106void
107xfs_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
Nathan Scott4aeb6642005-11-02 11:43:58 +1100114 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).
Nathan Scott4aeb6642005-11-02 11:43:58 +1100150 */
151void
152xfs_ichgtime_fast(
153 xfs_inode_t *ip,
154 struct inode *inode,
155 int flags)
156{
157 timespec_t *tvp;
158
159 /*
Christoph Hellwig42fe2b12006-01-11 15:35:17 +1100160 * 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 /*
Nathan Scott4aeb6642005-11-02 11:43:58 +1100166 * 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
Nathan Scott4aeb6642005-11-02 11:43:58 +1100172 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 }
Nathan Scott4aeb6642005-11-02 11:43:58 +1100177 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
199/*
200 * Pull the link count and size up from the xfs inode to the linux inode
201 */
202STATIC void
203validate_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
Jes Sorensen1b1dcc12006-01-09 15:59:24 -0800216 /* we're under i_mutex so i_size can't change under us */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 if (i_size_read(ip) != va.va_size)
218 i_size_write(ip, va.va_size);
219 }
220}
221
222/*
Nathan Scott446ada42006-01-11 15:35:44 +1100223 * 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 */
228STATIC int
229linvfs_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/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 * 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 */
261STATIC inline int
262has_fs_struct(struct task_struct *task)
263{
264 return (task->fs != init_task.fs);
265}
266
267STATIC int
268linvfs_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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 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
Nathan Scott446ada42006-01-11 15:35:44 +1100320 if (!error)
321 error = linvfs_init_security(vp, dir);
322
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 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
363STATIC int
364linvfs_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
373STATIC int
374linvfs_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
382STATIC struct dentry *
383linvfs_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
405STATIC int
406linvfs_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
433STATIC int
434linvfs_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
454STATIC int
455linvfs_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));
Christoph Hellwig0432dab2005-09-02 16:46:51 +1000470 va.va_mode = S_IFLNK |
471 (irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 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) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 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
485STATIC int
486linvfs_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
502STATIC int
503linvfs_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 */
Al Viro008b1502005-08-20 00:17:39 +0100535STATIC void *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536linvfs_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));
Al Viro008b1502005-08-20 00:17:39 +0100552 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 }
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));
Al Viro008b1502005-08-20 00:17:39 +0100559 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 }
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);
Al Viro008b1502005-08-20 00:17:39 +0100583 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584}
585
Nathan Scottcde410a2005-09-05 11:47:01 +1000586STATIC void
587linvfs_put_link(
588 struct dentry *dentry,
589 struct nameidata *nd,
590 void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591{
Nathan Scottcde410a2005-09-05 11:47:01 +1000592 char *s = nd_get_link(nd);
593
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 if (!IS_ERR(s))
595 kfree(s);
596}
597
598#ifdef CONFIG_XFS_POSIX_ACL
599STATIC int
600linvfs_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
616STATIC int
617linvfs_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
633STATIC int
634linvfs_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
691STATIC void
692linvfs_truncate(
693 struct inode *inode)
694{
695 block_truncate_page(inode->i_mapping, inode->i_size, linvfs_get_block);
696}
697
698STATIC int
699linvfs_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
729STATIC ssize_t
730linvfs_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
759STATIC ssize_t
760linvfs_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
779STATIC int
780linvfs_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
802struct 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
813struct 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
832struct 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};