Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5859d77e authored by Martin Brandenburg's avatar Martin Brandenburg Committed by Mike Marshall
Browse files

orangefs: use new getattr for revalidate and remove old getattr

parent 8f24928d
Loading
Loading
Loading
Loading
+1 −2
Original line number Original line Diff line number Diff line
@@ -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__);
+2 −2
Original line number Original line Diff line number Diff line
@@ -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);
+46 −321
Original line number Original line Diff line number Diff line
@@ -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 @@ int orangefs_inode_getattr(struct inode *inode, int new, int size)
	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