aboutsummaryrefslogtreecommitdiffstats
path: root/fs/orangefs
diff options
context:
space:
mode:
authorMartin Brandenburg <martin@omnibond.com>2016-01-28 10:19:40 -0500
committerMike Marshall <hubcap@omnibond.com>2016-01-28 15:08:40 -0500
commit99109822f5cbe6d530eb55193b25aa5348f6134d (patch)
tree5545d59702d9c2c2a28af01849a35f380ce01980 /fs/orangefs
parent394f647e3ad073dab19ba081501e4a0ca05302c4 (diff)
orangefs: Fix revalidate.
Previously, it would update a live inode. This was fixed, but it did not ever check that the inode attributes in the dcache are correct. This checks all inode attributes and rejects any that are not correct, which causes a lookup and thus a new getattr. Perhaps inode_operations->permission should replace or augment some of this. There is no actual caching, and this does a rather excessive amount of network operations back to the filesystem server. Signed-off-by: Martin Brandenburg <martin@omnibond.com> Signed-off-by: Mike Marshall <hubcap@omnibond.com>
Diffstat (limited to 'fs/orangefs')
-rw-r--r--fs/orangefs/dcache.c98
-rw-r--r--fs/orangefs/file.c4
-rw-r--r--fs/orangefs/inode.c6
-rw-r--r--fs/orangefs/orangefs-kernel.h2
-rw-r--r--fs/orangefs/orangefs-utils.c141
5 files changed, 187 insertions, 64 deletions
diff --git a/fs/orangefs/dcache.c b/fs/orangefs/dcache.c
index 0419981f773e..e8fb79de37c6 100644
--- a/fs/orangefs/dcache.c
+++ b/fs/orangefs/dcache.c
@@ -43,24 +43,34 @@ static int orangefs_revalidate_lookup(struct dentry *dentry)
43 43
44 err = service_operation(new_op, "orangefs_lookup", 44 err = service_operation(new_op, "orangefs_lookup",
45 get_interruptible_flag(parent_inode)); 45 get_interruptible_flag(parent_inode));
46 if (err) 46
47 goto out_drop; 47 /* Positive dentry: reject if error or not the same inode. */
48 48 if (inode) {
49 if (new_op->downcall.status != 0 || 49 if (err) {
50 !match_handle(new_op->downcall.resp.lookup.refn.khandle, inode)) { 50 gossip_debug(GOSSIP_DCACHE_DEBUG,
51 gossip_debug(GOSSIP_DCACHE_DEBUG, 51 "%s:%s:%d lookup failure.\n",
52 "%s:%s:%d " 52 __FILE__, __func__, __LINE__);
53 "lookup failure |%s| or no match |%s|.\n", 53 goto out_drop;
54 __FILE__, 54 }
55 __func__, 55 if (!match_handle(new_op->downcall.resp.lookup.refn.khandle,
56 __LINE__, 56 inode)) {
57 new_op->downcall.status ? "true" : "false", 57 gossip_debug(GOSSIP_DCACHE_DEBUG,
58 match_handle(new_op->downcall.resp.lookup.refn.khandle, 58 "%s:%s:%d no match.\n",
59 inode) ? "false" : "true"); 59 __FILE__, __func__, __LINE__);
60 gossip_debug(GOSSIP_DCACHE_DEBUG, 60 goto out_drop;
61 "%s:%s:%d revalidate failed\n", 61 }
62 __FILE__, __func__, __LINE__); 62
63 goto out_drop; 63 /* Negative dentry: reject if success or error other than ENOENT. */
64 } else {
65 gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: negative dentry.\n",
66 __func__);
67 if (!err || err != -ENOENT) {
68 if (new_op->downcall.status != 0)
69 gossip_debug(GOSSIP_DCACHE_DEBUG,
70 "%s:%s:%d lookup failure.\n",
71 __FILE__, __func__, __LINE__);
72 goto out_drop;
73 }
64 } 74 }
65 75
66 ret = 1; 76 ret = 1;
@@ -70,6 +80,8 @@ out_put_parent:
70 dput(parent_dentry); 80 dput(parent_dentry);
71 return ret; 81 return ret;
72out_drop: 82out_drop:
83 gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d revalidate failed\n",
84 __FILE__, __func__, __LINE__);
73 d_drop(dentry); 85 d_drop(dentry);
74 goto out_release_op; 86 goto out_release_op;
75} 87}
@@ -81,8 +93,7 @@ out_drop:
81 */ 93 */
82static int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags) 94static int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags)
83{ 95{
84 struct inode *inode; 96 int ret;
85 int ret = 0;
86 97
87 if (flags & LOOKUP_RCU) 98 if (flags & LOOKUP_RCU)
88 return -ECHILD; 99 return -ECHILD;
@@ -90,29 +101,42 @@ static int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags)
90 gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: called on dentry %p.\n", 101 gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: called on dentry %p.\n",
91 __func__, dentry); 102 __func__, dentry);
92 103
93 /* find inode from dentry */ 104 /* skip root handle lookups. */
94 if (!dentry->d_inode) { 105 if (dentry->d_inode && is_root_handle(dentry->d_inode))
95 gossip_debug(GOSSIP_DCACHE_DEBUG, 106 return 1;
96 "%s: negative dentry.\n", 107
97 __func__); 108 /*
98 goto out; 109 * If this passes, the positive dentry still exists or the negative
110 * dentry still does not exist.
111 */
112 if (!orangefs_revalidate_lookup(dentry)) {
113 d_drop(dentry);
114 return 0;
99 } 115 }
100 116
101 gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: inode valid.\n", __func__); 117 /* We do not need to continue with negative dentries. */
102 inode = dentry->d_inode; 118 if (!dentry->d_inode)
103
104 /* skip root handle lookups. */
105 if (is_root_handle(inode)) {
106 ret = 1;
107 goto out; 119 goto out;
108 }
109 120
110 /* lookup the object. */ 121 /* Now we must perform a getattr to validate the inode contents. */
111 if (orangefs_revalidate_lookup(dentry)) 122 ret = orangefs_inode_getattr(dentry->d_inode,
112 ret = 1; 123 ORANGEFS_ATTR_SYS_ALL_NOHINT, 1);
124 if (ret < 0) {
125 gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d getattr failure.\n",
126 __FILE__, __func__, __LINE__);
127 d_drop(dentry);
128 return 0;
129 }
130 if (ret == 0) {
131 d_drop(dentry);
132 return 0;
133 }
113 134
114out: 135out:
115 return ret; 136 gossip_debug(GOSSIP_DCACHE_DEBUG,
137 "%s: negative dentry or positive dentry and inode valid.\n",
138 __func__);
139 return 1;
116} 140}
117 141
118const struct dentry_operations orangefs_dentry_operations = { 142const struct dentry_operations orangefs_dentry_operations = {
diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c
index c585063d1100..7e6fe8d8ab2b 100644
--- a/fs/orangefs/file.c
+++ b/fs/orangefs/file.c
@@ -467,7 +467,7 @@ static ssize_t orangefs_file_write_iter(struct kiocb *iocb, struct iov_iter *ite
467 /* Make sure generic_write_checks sees an up to date inode size. */ 467 /* Make sure generic_write_checks sees an up to date inode size. */
468 if (file->f_flags & O_APPEND) { 468 if (file->f_flags & O_APPEND) {
469 rc = orangefs_inode_getattr(file->f_mapping->host, 469 rc = orangefs_inode_getattr(file->f_mapping->host,
470 ORANGEFS_ATTR_SYS_SIZE); 470 ORANGEFS_ATTR_SYS_SIZE, 0);
471 if (rc) { 471 if (rc) {
472 gossip_err("%s: orangefs_inode_getattr failed, rc:%zd:.\n", 472 gossip_err("%s: orangefs_inode_getattr failed, rc:%zd:.\n",
473 __func__, rc); 473 __func__, rc);
@@ -681,7 +681,7 @@ static loff_t orangefs_file_llseek(struct file *file, loff_t offset, int origin)
681 * NOTE: We are only interested in file size here, 681 * NOTE: We are only interested in file size here,
682 * so we set mask accordingly. 682 * so we set mask accordingly.
683 */ 683 */
684 ret = orangefs_inode_getattr(inode, ORANGEFS_ATTR_SYS_SIZE); 684 ret = orangefs_inode_getattr(inode, ORANGEFS_ATTR_SYS_SIZE, 0);
685 if (ret) { 685 if (ret) {
686 gossip_debug(GOSSIP_FILE_DEBUG, 686 gossip_debug(GOSSIP_FILE_DEBUG,
687 "%s:%s:%d calling make bad inode\n", 687 "%s:%s:%d calling make bad inode\n",
diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
index 4724c92b61ac..040cd95b51c2 100644
--- a/fs/orangefs/inode.c
+++ b/fs/orangefs/inode.c
@@ -273,7 +273,7 @@ int orangefs_getattr(struct vfsmount *mnt,
273 * fields/attributes of the inode would be refreshed. So again, we 273 * fields/attributes of the inode would be refreshed. So again, we
274 * dont have too much of a choice but refresh all the attributes. 274 * dont have too much of a choice but refresh all the attributes.
275 */ 275 */
276 ret = orangefs_inode_getattr(inode, ORANGEFS_ATTR_SYS_ALL_NOHINT); 276 ret = orangefs_inode_getattr(inode, ORANGEFS_ATTR_SYS_ALL_NOHINT, 0);
277 if (ret == 0) { 277 if (ret == 0) {
278 generic_fillattr(inode, kstat); 278 generic_fillattr(inode, kstat);
279 /* override block size reported to stat */ 279 /* override block size reported to stat */
@@ -392,7 +392,7 @@ struct inode *orangefs_iget(struct super_block *sb, struct orangefs_object_kref
392 if (!inode || !(inode->i_state & I_NEW)) 392 if (!inode || !(inode->i_state & I_NEW))
393 return inode; 393 return inode;
394 394
395 error = orangefs_inode_getattr(inode, ORANGEFS_ATTR_SYS_ALL_NOHINT); 395 error = orangefs_inode_getattr(inode, ORANGEFS_ATTR_SYS_ALL_NOHINT, 0);
396 if (error) { 396 if (error) {
397 iget_failed(inode); 397 iget_failed(inode);
398 return ERR_PTR(error); 398 return ERR_PTR(error);
@@ -437,7 +437,7 @@ struct inode *orangefs_new_inode(struct super_block *sb, struct inode *dir,
437 orangefs_set_inode(inode, ref); 437 orangefs_set_inode(inode, ref);
438 inode->i_ino = hash; /* needed for stat etc */ 438 inode->i_ino = hash; /* needed for stat etc */
439 439
440 error = orangefs_inode_getattr(inode, ORANGEFS_ATTR_SYS_ALL_NOHINT); 440 error = orangefs_inode_getattr(inode, ORANGEFS_ATTR_SYS_ALL_NOHINT, 0);
441 if (error) 441 if (error)
442 goto out_iput; 442 goto out_iput;
443 443
diff --git a/fs/orangefs/orangefs-kernel.h b/fs/orangefs/orangefs-kernel.h
index 9c876762f825..3e258554688d 100644
--- a/fs/orangefs/orangefs-kernel.h
+++ b/fs/orangefs/orangefs-kernel.h
@@ -561,7 +561,7 @@ int orangefs_inode_setxattr(struct inode *inode,
561 size_t size, 561 size_t size,
562 int flags); 562 int flags);
563 563
564int orangefs_inode_getattr(struct inode *inode, __u32 mask); 564int orangefs_inode_getattr(struct inode *inode, __u32 mask, int check);
565 565
566int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr); 566int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr);
567 567
diff --git a/fs/orangefs/orangefs-utils.c b/fs/orangefs/orangefs-utils.c
index 035f050ae0e8..6cf29a439211 100644
--- a/fs/orangefs/orangefs-utils.c
+++ b/fs/orangefs/orangefs-utils.c
@@ -353,11 +353,91 @@ static inline int copy_attributes_from_inode(struct inode *inode,
353 return 0; 353 return 0;
354} 354}
355 355
356static int compare_attributes_to_inode(struct inode *inode,
357 struct ORANGEFS_sys_attr_s *attrs,
358 char *symname)
359{
360 struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
361 loff_t inode_size, rounded_up_size;
362
363 /* Compare file size. */
364
365 switch (attrs->objtype) {
366 case ORANGEFS_TYPE_METAFILE:
367 if(inode->i_flags != orangefs_inode_flags(attrs))
368 return 0;
369 inode_size = attrs->size;
370 rounded_up_size = inode_size + (4096 - (inode_size % 4096));
371 if (inode->i_bytes != inode_size ||
372 inode->i_blocks != rounded_up_size/512)
373 return 0;
374 break;
375 case ORANGEFS_TYPE_SYMLINK:
376 if (symname && strlen(symname) != inode->i_size)
377 return 0;
378 break;
379 default:
380 if (inode->i_size != PAGE_CACHE_SIZE &&
381 inode_get_bytes(inode) != PAGE_CACHE_SIZE)
382 return 0;
383 }
384
385 /* Compare general attributes. */
386
387 if (!uid_eq(inode->i_uid, make_kuid(&init_user_ns, attrs->owner)) ||
388 !gid_eq(inode->i_gid, make_kgid(&init_user_ns, attrs->group)) ||
389 inode->i_atime.tv_sec != attrs->atime ||
390 inode->i_mtime.tv_sec != attrs->mtime ||
391 inode->i_ctime.tv_sec != attrs->ctime ||
392 inode->i_atime.tv_nsec != 0 ||
393 inode->i_mtime.tv_nsec != 0 ||
394 inode->i_ctime.tv_nsec != 0)
395 return 0;
396
397 if ((inode->i_mode & ~(S_ISVTX|S_IFREG|S_IFDIR|S_IFLNK)) !=
398 orangefs_inode_perms(attrs))
399 return 0;
400
401 if (is_root_handle(inode))
402 if (!(inode->i_mode & S_ISVTX))
403 return 0;
404
405 /* Compare file type. */
406
407 switch (attrs->objtype) {
408 case ORANGEFS_TYPE_METAFILE:
409 if (!(inode->i_mode & S_IFREG))
410 return 0;
411 break;
412 case ORANGEFS_TYPE_DIRECTORY:
413 if (!(inode->i_mode & S_IFDIR))
414 return 0;
415 if (inode->i_nlink != 1)
416 return 0;
417 break;
418 case ORANGEFS_TYPE_SYMLINK:
419 if (!(inode->i_mode & S_IFLNK))
420 return 0;
421 if (orangefs_inode && symname)
422 if (strcmp(orangefs_inode->link_target, symname))
423 return 0;
424 break;
425 default:
426 gossip_err("orangefs: compare_attributes_to_inode: got invalid attribute type %x\n",
427 attrs->objtype);
428
429 }
430
431 return 1;
432}
433
356/* 434/*
357 * issues a orangefs getattr request and fills in the appropriate inode 435 * Issues a orangefs getattr request and fills in the appropriate inode
358 * attributes if successful. returns 0 on success; -errno otherwise 436 * attributes if successful. When check is 0, returns 0 on success and -errno
437 * otherwise. When check is 1, returns 1 on success where the inode is valid
438 * and 0 on success where the inode is stale and -errno otherwise.
359 */ 439 */
360int orangefs_inode_getattr(struct inode *inode, __u32 getattr_mask) 440int orangefs_inode_getattr(struct inode *inode, __u32 getattr_mask, int check)
361{ 441{
362 struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 442 struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
363 struct orangefs_kernel_op_s *new_op; 443 struct orangefs_kernel_op_s *new_op;
@@ -379,27 +459,46 @@ int orangefs_inode_getattr(struct inode *inode, __u32 getattr_mask)
379 if (ret != 0) 459 if (ret != 0)
380 goto out; 460 goto out;
381 461
382 if (copy_attributes_to_inode(inode, 462 if (check) {
383 &new_op->downcall.resp.getattr.attributes, 463 ret = compare_attributes_to_inode(inode,
384 new_op->downcall.resp.getattr.link_target)) { 464 &new_op->downcall.resp.getattr.attributes,
385 gossip_err("%s: failed to copy attributes\n", __func__); 465 new_op->downcall.resp.getattr.link_target);
386 ret = -ENOENT;
387 goto out;
388 }
389 466
390 /* 467 if (new_op->downcall.resp.getattr.attributes.objtype ==
391 * Store blksize in orangefs specific part of inode structure; we are 468 ORANGEFS_TYPE_METAFILE) {
392 * only going to use this to report to stat to make sure it doesn't 469 if (orangefs_inode->blksize !=
393 * perturb any inode related code paths. 470 new_op->downcall.resp.getattr.attributes.blksize)
394 */ 471 ret = 0;
395 if (new_op->downcall.resp.getattr.attributes.objtype == 472 } else {
396 ORANGEFS_TYPE_METAFILE) { 473 if (orangefs_inode->blksize != 1 << inode->i_blkbits)
397 orangefs_inode->blksize = 474 ret = 0;
398 new_op->downcall.resp.getattr.attributes.blksize; 475 }
399 } else { 476 } else {
400 /* mimic behavior of generic_fillattr() for other types. */ 477 if (copy_attributes_to_inode(inode,
401 orangefs_inode->blksize = (1 << inode->i_blkbits); 478 &new_op->downcall.resp.getattr.attributes,
479 new_op->downcall.resp.getattr.link_target)) {
480 gossip_err("%s: failed to copy attributes\n", __func__);
481 ret = -ENOENT;
482 goto out;
483 }
402 484
485 /*
486 * Store blksize in orangefs specific part of inode structure;
487 * we are only going to use this to report to stat to make sure
488 * it doesn't perturb any inode related code paths.
489 */
490 if (new_op->downcall.resp.getattr.attributes.objtype ==
491 ORANGEFS_TYPE_METAFILE) {
492 orangefs_inode->blksize = new_op->downcall.resp.
493 getattr.attributes.blksize;
494 } else {
495 /*
496 * mimic behavior of generic_fillattr() for other file
497 * types.
498 */
499 orangefs_inode->blksize = (1 << inode->i_blkbits);
500
501 }
403 } 502 }
404 503
405out: 504out: