orangefs: use new getattr for revalidate and remove old getattr

Signed-off-by: Martin Brandenburg <martin@omnibond.com>
Signed-off-by: Mike Marshall <hubcap@omnibond.com>
This commit is contained in:
Martin Brandenburg 2016-03-17 15:15:16 -04:00 committed by Mike Marshall
parent 8f24928d19
commit 5859d77e56
3 changed files with 49 additions and 325 deletions

View File

@ -117,8 +117,7 @@ static int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags)
/* Now we must perform a getattr to validate the inode contents. */ /* Now we must perform a getattr to validate the inode contents. */
ret = orangefs_inode_old_getattr(dentry->d_inode, ret = orangefs_inode_check_changed(dentry->d_inode);
ORANGEFS_ATTR_SYS_TYPE|ORANGEFS_ATTR_SYS_LNK_TARGET, 1);
if (ret < 0) { if (ret < 0) {
gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d getattr failure.\n", gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d getattr failure.\n",
__FILE__, __func__, __LINE__); __FILE__, __func__, __LINE__);

View File

@ -544,10 +544,10 @@ int orangefs_inode_setxattr(struct inode *inode,
size_t size, size_t size,
int flags); int flags);
int orangefs_inode_old_getattr(struct inode *inode, __u32 mask, int check);
int orangefs_inode_getattr(struct inode *inode, int new, int size); int orangefs_inode_getattr(struct inode *inode, int new, int size);
int orangefs_inode_check_changed(struct inode *inode);
int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr); int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr);
void orangefs_make_bad_inode(struct inode *inode); void orangefs_make_bad_inode(struct inode *inode);

View File

@ -129,141 +129,6 @@ static int orangefs_inode_perms(struct ORANGEFS_sys_attr_s *attrs)
return perm_mode; return perm_mode;
} }
/* NOTE: symname is ignored unless the inode is a sym link */
static int copy_attributes_to_inode(struct inode *inode,
struct ORANGEFS_sys_attr_s *attrs,
char *symname)
{
int ret = -1;
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
loff_t inode_size = 0;
loff_t rounded_up_size = 0;
/*
* arbitrarily set the inode block size; FIXME: we need to
* resolve the difference between the reported inode blocksize
* and the PAGE_CACHE_SIZE, since our block count will always
* be wrong.
*
* For now, we're setting the block count to be the proper
* number assuming the block size is 512 bytes, and the size is
* rounded up to the nearest 4K. This is apparently required
* to get proper size reports from the 'du' shell utility.
*
* changing the inode->i_blkbits to something other than
* PAGE_CACHE_SHIFT breaks mmap/execution as we depend on that.
*/
gossip_debug(GOSSIP_UTILS_DEBUG,
"attrs->mask = %x (objtype = %s)\n",
attrs->mask,
attrs->objtype == ORANGEFS_TYPE_METAFILE ? "file" :
attrs->objtype == ORANGEFS_TYPE_DIRECTORY ? "directory" :
attrs->objtype == ORANGEFS_TYPE_SYMLINK ? "symlink" :
"invalid/unknown");
switch (attrs->objtype) {
case ORANGEFS_TYPE_METAFILE:
inode->i_flags = orangefs_inode_flags(attrs);
if (attrs->mask & ORANGEFS_ATTR_SYS_SIZE) {
inode_size = (loff_t) attrs->size;
rounded_up_size =
(inode_size + (4096 - (inode_size % 4096)));
spin_lock(&inode->i_lock);
inode->i_bytes = inode_size;
inode->i_blocks =
(unsigned long)(rounded_up_size / 512);
spin_unlock(&inode->i_lock);
/*
* NOTE: make sure all the places we're called
* from have the inode->i_sem lock. We're fine
* in 99% of the cases since we're mostly
* called from a lookup.
*/
inode->i_size = inode_size;
}
break;
case ORANGEFS_TYPE_SYMLINK:
if (symname != NULL) {
inode->i_size = (loff_t) strlen(symname);
break;
}
/*FALLTHRU*/
default:
inode->i_size = PAGE_CACHE_SIZE;
spin_lock(&inode->i_lock);
inode_set_bytes(inode, inode->i_size);
spin_unlock(&inode->i_lock);
break;
}
inode->i_uid = make_kuid(&init_user_ns, attrs->owner);
inode->i_gid = make_kgid(&init_user_ns, attrs->group);
inode->i_atime.tv_sec = (time64_t) attrs->atime;
inode->i_mtime.tv_sec = (time64_t) attrs->mtime;
inode->i_ctime.tv_sec = (time64_t) attrs->ctime;
inode->i_atime.tv_nsec = 0;
inode->i_mtime.tv_nsec = 0;
inode->i_ctime.tv_nsec = 0;
inode->i_mode = orangefs_inode_perms(attrs);
if (is_root_handle(inode)) {
/* special case: mark the root inode as sticky */
inode->i_mode |= S_ISVTX;
gossip_debug(GOSSIP_UTILS_DEBUG,
"Marking inode %pU as sticky\n",
get_khandle_from_ino(inode));
}
switch (attrs->objtype) {
case ORANGEFS_TYPE_METAFILE:
inode->i_mode |= S_IFREG;
ret = 0;
break;
case ORANGEFS_TYPE_DIRECTORY:
inode->i_mode |= S_IFDIR;
/* NOTE: we have no good way to keep nlink consistent
* for directories across clients; keep constant at 1.
* Why 1? If we go with 2, then find(1) gets confused
* and won't work properly withouth the -noleaf option
*/
set_nlink(inode, 1);
ret = 0;
break;
case ORANGEFS_TYPE_SYMLINK:
inode->i_mode |= S_IFLNK;
/* copy link target to inode private data */
if (orangefs_inode && symname) {
strncpy(orangefs_inode->link_target,
symname,
ORANGEFS_NAME_MAX);
gossip_debug(GOSSIP_UTILS_DEBUG,
"Copied attr link target %s\n",
orangefs_inode->link_target);
}
gossip_debug(GOSSIP_UTILS_DEBUG,
"symlink mode %o\n",
inode->i_mode);
ret = 0;
break;
default:
gossip_err("orangefs: copy_attributes_to_inode: got invalid attribute type %x\n",
attrs->objtype);
}
gossip_debug(GOSSIP_UTILS_DEBUG,
"orangefs: copy_attributes_to_inode: setting i_mode to %o, i_size to %lu\n",
inode->i_mode,
(unsigned long)i_size_read(inode));
return ret;
}
/* /*
* NOTE: in kernel land, we never use the sys_attr->link_target for * NOTE: in kernel land, we never use the sys_attr->link_target for
* anything, so don't bother copying it into the sys_attr object here. * anything, so don't bother copying it into the sys_attr object here.
@ -351,192 +216,6 @@ static inline int copy_attributes_from_inode(struct inode *inode,
return 0; return 0;
} }
static int compare_attributes_to_inode(struct inode *inode,
struct ORANGEFS_sys_attr_s *attrs,
char *symname,
int mask)
{
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
loff_t inode_size, rounded_up_size;
/* Much of what happens below relies on the type being around. */
if (!(mask & ORANGEFS_ATTR_SYS_TYPE))
return 0;
if (attrs->objtype == ORANGEFS_TYPE_METAFILE &&
inode->i_flags != orangefs_inode_flags(attrs))
return 0;
/* Compare file size. */
switch (attrs->objtype) {
case ORANGEFS_TYPE_METAFILE:
if (mask & ORANGEFS_ATTR_SYS_SIZE) {
inode_size = attrs->size;
rounded_up_size = inode_size +
(4096 - (inode_size % 4096));
if (inode->i_bytes != inode_size ||
inode->i_blocks != rounded_up_size/512)
return 0;
}
break;
case ORANGEFS_TYPE_SYMLINK:
if (mask & ORANGEFS_ATTR_SYS_SIZE)
if (symname && strlen(symname) != inode->i_size)
return 0;
break;
default:
if (inode->i_size != PAGE_CACHE_SIZE &&
inode_get_bytes(inode) != PAGE_CACHE_SIZE)
return 0;
}
/* Compare general attributes. */
if (mask & ORANGEFS_ATTR_SYS_UID &&
!uid_eq(inode->i_uid, make_kuid(&init_user_ns, attrs->owner)))
return 0;
if (mask & ORANGEFS_ATTR_SYS_GID &&
!gid_eq(inode->i_gid, make_kgid(&init_user_ns, attrs->group)))
return 0;
if (mask & ORANGEFS_ATTR_SYS_ATIME &&
inode->i_atime.tv_sec != attrs->atime)
return 0;
if (mask & ORANGEFS_ATTR_SYS_MTIME &&
inode->i_atime.tv_sec != attrs->mtime)
return 0;
if (mask & ORANGEFS_ATTR_SYS_CTIME &&
inode->i_atime.tv_sec != attrs->ctime)
return 0;
if (inode->i_atime.tv_nsec != 0 ||
inode->i_mtime.tv_nsec != 0 ||
inode->i_ctime.tv_nsec != 0)
return 0;
if (mask & ORANGEFS_ATTR_SYS_PERM &&
(inode->i_mode & ~(S_ISVTX|S_IFREG|S_IFDIR|S_IFLNK)) !=
orangefs_inode_perms(attrs))
return 0;
if (is_root_handle(inode))
if (!(inode->i_mode & S_ISVTX))
return 0;
/* Compare file type. */
switch (attrs->objtype) {
case ORANGEFS_TYPE_METAFILE:
if (!S_ISREG(inode->i_mode))
return 0;
break;
case ORANGEFS_TYPE_DIRECTORY:
if (!S_ISDIR(inode->i_mode))
return 0;
if (inode->i_nlink != 1)
return 0;
break;
case ORANGEFS_TYPE_SYMLINK:
if (!S_ISLNK(inode->i_mode))
return 0;
if (orangefs_inode && symname &&
mask & ORANGEFS_ATTR_SYS_LNK_TARGET)
if (strcmp(orangefs_inode->link_target, symname))
return 0;
break;
default:
gossip_err("orangefs: compare_attributes_to_inode: got invalid attribute type %x\n",
attrs->objtype);
}
return 1;
}
/*
* Issues a orangefs getattr request and fills in the appropriate inode
* attributes if successful. When check is 0, returns 0 on success and -errno
* otherwise. When check is 1, returns 1 on success where the inode is valid
* and 0 on success where the inode is stale and -errno otherwise.
*/
int orangefs_inode_old_getattr(struct inode *inode, __u32 getattr_mask,
int check)
{
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
struct orangefs_kernel_op_s *new_op;
int ret = -EINVAL;
gossip_debug(GOSSIP_UTILS_DEBUG,
"%s: called on inode %pU\n",
__func__,
get_khandle_from_ino(inode));
new_op = op_alloc(ORANGEFS_VFS_OP_GETATTR);
if (!new_op)
return -ENOMEM;
new_op->upcall.req.getattr.refn = orangefs_inode->refn;
new_op->upcall.req.getattr.mask = getattr_mask;
ret = service_operation(new_op, __func__,
get_interruptible_flag(inode));
if (ret != 0)
goto out;
if (check) {
ret = compare_attributes_to_inode(inode,
&new_op->downcall.resp.getattr.attributes,
new_op->downcall.resp.getattr.link_target,
getattr_mask);
if (new_op->downcall.resp.getattr.attributes.objtype ==
ORANGEFS_TYPE_METAFILE) {
if (orangefs_inode->blksize !=
new_op->downcall.resp.getattr.attributes.blksize)
ret = 0;
} else {
if (orangefs_inode->blksize != 1 << inode->i_blkbits)
ret = 0;
}
} else {
if (copy_attributes_to_inode(inode,
&new_op->downcall.resp.getattr.attributes,
new_op->downcall.resp.getattr.link_target)) {
gossip_err("%s: failed to copy attributes\n", __func__);
ret = -ENOENT;
goto out;
}
/*
* Store blksize in orangefs specific part of inode structure;
* we are only going to use this to report to stat to make sure
* it doesn't perturb any inode related code paths.
*/
if (new_op->downcall.resp.getattr.attributes.objtype ==
ORANGEFS_TYPE_METAFILE) {
orangefs_inode->blksize = new_op->downcall.resp.
getattr.attributes.blksize;
} else {
/*
* mimic behavior of generic_fillattr() for other file
* types.
*/
orangefs_inode->blksize = (1 << inode->i_blkbits);
}
}
out:
gossip_debug(GOSSIP_UTILS_DEBUG,
"Getattr on handle %pU, "
"fsid %d\n (inode ct = %d) returned %d\n",
&orangefs_inode->refn.khandle,
orangefs_inode->refn.fs_id,
(int)atomic_read(&inode->i_count),
ret);
op_release(new_op);
return ret;
}
static int orangefs_inode_type(enum orangefs_ds_type objtype) static int orangefs_inode_type(enum orangefs_ds_type objtype)
{ {
if (objtype == ORANGEFS_TYPE_METAFILE) if (objtype == ORANGEFS_TYPE_METAFILE)
@ -655,6 +334,52 @@ out:
return ret; return ret;
} }
int orangefs_inode_check_changed(struct inode *inode)
{
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
struct orangefs_kernel_op_s *new_op;
int ret;
gossip_debug(GOSSIP_UTILS_DEBUG, "%s: called on inode %pU\n", __func__,
get_khandle_from_ino(inode));
new_op = op_alloc(ORANGEFS_VFS_OP_GETATTR);
if (!new_op)
return -ENOMEM;
new_op->upcall.req.getattr.refn = orangefs_inode->refn;
new_op->upcall.req.getattr.mask = ORANGEFS_ATTR_SYS_TYPE |
ORANGEFS_ATTR_SYS_LNK_TARGET;
ret = service_operation(new_op, __func__,
get_interruptible_flag(inode));
if (ret != 0)
goto out;
ret = orangefs_inode_type(new_op->
downcall.resp.getattr.attributes.objtype);
/*
* If the inode type or symlink target have changed then this
* inode is stale.
*/
if (ret == -1 || !(inode->i_mode & ret)) {
orangefs_make_bad_inode(inode);
ret = 1;
goto out;
}
if (ret == S_IFLNK && strncmp(orangefs_inode->link_target,
new_op->downcall.resp.getattr.link_target,
ORANGEFS_NAME_MAX)) {
orangefs_make_bad_inode(inode);
ret = 1;
goto out;
}
ret = 0;
out:
op_release(new_op);
return ret;
}
/* /*
* issues a orangefs setattr request to make sure the new attribute values * issues a orangefs setattr request to make sure the new attribute values
* take effect if successful. returns 0 on success; -errno otherwise * take effect if successful. returns 0 on success; -errno otherwise