From 3c9cf98d7b4f27e4303ea6e67db7f0c343a575b6 Mon Sep 17 00:00:00 2001 From: Martin Brandenburg Date: Tue, 15 Mar 2016 11:28:20 -0400 Subject: orangefs: rename orangefs_inode_getattr to orangefs_inode_old_getattr This is motivated by orangefs_inode_old_getattr's habit of writing over live inodes. Signed-off-by: Martin Brandenburg Signed-off-by: Mike Marshall --- fs/orangefs/dcache.c | 2 +- fs/orangefs/file.c | 7 +-- fs/orangefs/inode.c | 9 ++-- fs/orangefs/orangefs-kernel.h | 4 +- fs/orangefs/orangefs-utils.c | 121 +++++++++++++++++++++++++++++++++++++++++- 5 files changed, 133 insertions(+), 10 deletions(-) (limited to 'fs/orangefs') diff --git a/fs/orangefs/dcache.c b/fs/orangefs/dcache.c index 2de92b71d861..cc5487a1d040 100644 --- a/fs/orangefs/dcache.c +++ b/fs/orangefs/dcache.c @@ -117,7 +117,7 @@ static int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags) /* Now we must perform a getattr to validate the inode contents. */ - ret = orangefs_inode_getattr(dentry->d_inode, + ret = orangefs_inode_old_getattr(dentry->d_inode, ORANGEFS_ATTR_SYS_TYPE|ORANGEFS_ATTR_SYS_LNK_TARGET, 1); if (ret < 0) { gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d getattr failure.\n", diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c index 9b561b7894b3..3aff671534d0 100644 --- a/fs/orangefs/file.c +++ b/fs/orangefs/file.c @@ -455,10 +455,10 @@ static ssize_t orangefs_file_write_iter(struct kiocb *iocb, struct iov_iter *ite /* Make sure generic_write_checks sees an up to date inode size. */ if (file->f_flags & O_APPEND) { - rc = orangefs_inode_getattr(file->f_mapping->host, + rc = orangefs_inode_old_getattr(file->f_mapping->host, ORANGEFS_ATTR_SYS_SIZE, 0); if (rc) { - gossip_err("%s: orangefs_inode_getattr failed, rc:%zd:.\n", + gossip_err("%s: orangefs_inode_old_getattr failed, rc:%zd:.\n", __func__, rc); goto out; } @@ -670,7 +670,8 @@ static loff_t orangefs_file_llseek(struct file *file, loff_t offset, int origin) * NOTE: We are only interested in file size here, * so we set mask accordingly. */ - ret = orangefs_inode_getattr(inode, ORANGEFS_ATTR_SYS_SIZE, 0); + ret = orangefs_inode_old_getattr(inode, + ORANGEFS_ATTR_SYS_SIZE, 0); if (ret) { gossip_debug(GOSSIP_FILE_DEBUG, "%s:%s:%d calling make bad inode\n", diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c index a45625240b17..fd591d44a97d 100644 --- a/fs/orangefs/inode.c +++ b/fs/orangefs/inode.c @@ -268,7 +268,8 @@ int orangefs_getattr(struct vfsmount *mnt, "orangefs_getattr: called on %s\n", dentry->d_name.name); - ret = orangefs_inode_getattr(inode, ORANGEFS_ATTR_SYS_ALL_NOHINT, 0); + ret = orangefs_inode_old_getattr(inode, ORANGEFS_ATTR_SYS_ALL_NOHINT, + 0); if (ret == 0) { generic_fillattr(inode, kstat); @@ -299,7 +300,7 @@ int orangefs_permission(struct inode *inode, int mask) gossip_debug(GOSSIP_INODE_DEBUG, "%s: refreshing\n", __func__); /* Make sure the permission (and other common attrs) are up to date. */ - ret = orangefs_inode_getattr(inode, + ret = orangefs_inode_old_getattr(inode, ORANGEFS_ATTR_SYS_ALL_NOHINT_NOSIZE, 0); if (ret < 0) return ret; @@ -401,7 +402,7 @@ struct inode *orangefs_iget(struct super_block *sb, struct orangefs_object_kref if (!inode || !(inode->i_state & I_NEW)) return inode; - error = orangefs_inode_getattr(inode, + error = orangefs_inode_old_getattr(inode, ORANGEFS_ATTR_SYS_ALL_NOHINT_NOSIZE, 0); if (error) { iget_failed(inode); @@ -447,7 +448,7 @@ struct inode *orangefs_new_inode(struct super_block *sb, struct inode *dir, orangefs_set_inode(inode, ref); inode->i_ino = hash; /* needed for stat etc */ - error = orangefs_inode_getattr(inode, + error = orangefs_inode_old_getattr(inode, ORANGEFS_ATTR_SYS_ALL_NOHINT_NOSIZE, 0); if (error) goto out_iput; diff --git a/fs/orangefs/orangefs-kernel.h b/fs/orangefs/orangefs-kernel.h index 784629870717..276685cdf38d 100644 --- a/fs/orangefs/orangefs-kernel.h +++ b/fs/orangefs/orangefs-kernel.h @@ -544,7 +544,9 @@ int orangefs_inode_setxattr(struct inode *inode, size_t size, int flags); -int orangefs_inode_getattr(struct inode *inode, __u32 mask, int check); +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_setattr(struct inode *inode, struct iattr *iattr); diff --git a/fs/orangefs/orangefs-utils.c b/fs/orangefs/orangefs-utils.c index df4ad04407e2..59c51e2c5a71 100644 --- a/fs/orangefs/orangefs-utils.c +++ b/fs/orangefs/orangefs-utils.c @@ -458,7 +458,8 @@ static int compare_attributes_to_inode(struct inode *inode, * 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_getattr(struct inode *inode, __u32 getattr_mask, int check) +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; @@ -536,6 +537,124 @@ out: return ret; } +static int orangefs_inode_type(enum orangefs_ds_type objtype) +{ + if (objtype == ORANGEFS_TYPE_METAFILE) + return S_IFREG; + else if (objtype == ORANGEFS_TYPE_DIRECTORY) + return S_IFDIR; + else if (objtype == ORANGEFS_TYPE_SYMLINK) + return S_IFLNK; + else + return -1; +} + +int orangefs_inode_getattr(struct inode *inode, int new, int size) +{ + struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); + struct orangefs_kernel_op_s *new_op; + loff_t inode_size, rounded_up_size; + 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 = size ? + ORANGEFS_ATTR_SYS_ALL_NOHINT : ORANGEFS_ATTR_SYS_ALL_NOHINT_NOSIZE; + + 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 (!new) { + /* + * 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 = -ESTALE; + 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 = -ESTALE; + goto out; + } + } + + switch (ret) { + case S_IFREG: + inode->i_flags = orangefs_inode_flags(&new_op-> + downcall.resp.getattr.attributes); + if (size) { + inode_size = (loff_t)new_op-> + downcall.resp.getattr.attributes.size; + rounded_up_size = + (inode_size + (4096 - (inode_size % 4096))); + inode->i_size = inode_size; + orangefs_inode->blksize = + new_op->downcall.resp.getattr.attributes.blksize; + spin_lock(&inode->i_lock); + inode->i_bytes = inode_size; + inode->i_blocks = + (unsigned long)(rounded_up_size / 512); + spin_unlock(&inode->i_lock); + } + break; + case S_IFDIR: + inode->i_size = PAGE_CACHE_SIZE; + orangefs_inode->blksize = (1 << inode->i_blkbits); + spin_lock(&inode->i_lock); + inode_set_bytes(inode, inode->i_size); + spin_unlock(&inode->i_lock); + set_nlink(inode, 1); + break; + case S_IFLNK: + if (new) { + inode->i_size = (loff_t)strlen(new_op-> + downcall.resp.getattr.link_target); + orangefs_inode->blksize = (1 << inode->i_blkbits); + strlcpy(orangefs_inode->link_target, + new_op->downcall.resp.getattr.link_target, + ORANGEFS_NAME_MAX); + } + break; + } + + inode->i_uid = make_kuid(&init_user_ns, new_op-> + downcall.resp.getattr.attributes.owner); + inode->i_gid = make_kgid(&init_user_ns, new_op-> + downcall.resp.getattr.attributes.group); + inode->i_atime.tv_sec = (time64_t)new_op-> + downcall.resp.getattr.attributes.atime; + inode->i_mtime.tv_sec = (time64_t)new_op-> + downcall.resp.getattr.attributes.mtime; + inode->i_ctime.tv_sec = (time64_t)new_op-> + downcall.resp.getattr.attributes.ctime; + inode->i_atime.tv_nsec = 0; + inode->i_mtime.tv_nsec = 0; + inode->i_ctime.tv_nsec = 0; + + /* special case: mark the root inode as sticky */ + inode->i_mode = ret | (is_root_handle(inode) ? S_ISVTX : 0) | + orangefs_inode_perms(&new_op->downcall.resp.getattr.attributes); + + ret = 0; +out: + op_release(new_op); + return ret; +} + /* * issues a orangefs setattr request to make sure the new attribute values * take effect if successful. returns 0 on success; -errno otherwise -- cgit v1.2.3