diff options
author | Martin Brandenburg <martin@omnibond.com> | 2018-02-13 23:13:46 +0300 |
---|---|---|
committer | Mike Marshall <hubcap@omnibond.com> | 2019-05-03 21:32:38 +0300 |
commit | afd9fb2a31797b4c787034294a4062df0c19c37e (patch) | |
tree | 08bc9f1eaab32d5561519af8f9b1ba2d5ee846ac /fs/orangefs/inode.c | |
parent | df2d7337b570c34e051a2412f716743277ccf9c8 (diff) | |
download | linux-afd9fb2a31797b4c787034294a4062df0c19c37e.tar.xz |
orangefs: reorganize setattr functions to track attribute changes
OrangeFS accepts a mask indicating which attributes were changed. The
kernel must not set any bits except those that were actually changed.
The kernel must set the uid/gid of the request to the actual uid/gid
responsible for the change.
Code path for notify_change initiated setattrs is
orangefs_setattr(dentry, iattr)
-> __orangefs_setattr(inode, iattr)
In kernel changes are initiated by calling __orangefs_setattr.
Code path for writeback is
orangefs_write_inode
-> orangefs_inode_setattr
attr_valid and attr_uid and attr_gid change together under i_lock.
I_DIRTY changes separately.
__orangefs_setattr
lock
if needs to be cleaned first, unlock and retry
set attr_valid
copy data in
unlock
mark_inode_dirty
orangefs_inode_setattr
lock
copy attributes out
unlock
clear getattr_time
# __writeback_single_inode clears dirty
orangefs_inode_getattr
# possible to get here with attr_valid set and not dirty
lock
if getattr_time ok or attr_valid set, unlock and return
unlock
do server operation
# another thread may getattr or setattr, so check for that
lock
if getattr_time ok or attr_valid, unlock and return
else, copy in
update getattr_time
unlock
Signed-off-by: Martin Brandenburg <martin@omnibond.com>
Signed-off-by: Mike Marshall <hubcap@omnibond.com>
Diffstat (limited to 'fs/orangefs/inode.c')
-rw-r--r-- | fs/orangefs/inode.c | 76 |
1 files changed, 61 insertions, 15 deletions
diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c index 2e630c1f7ae2..2708bf8af9cf 100644 --- a/fs/orangefs/inode.c +++ b/fs/orangefs/inode.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * (C) 2001 Clemson University and The University of Chicago + * Copyright 2018 Omnibond Systems, L.L.C. * * See COPYING in top-level directory. */ @@ -202,22 +203,31 @@ static int orangefs_setattr_size(struct inode *inode, struct iattr *iattr) return ret; } -/* - * Change attributes of an object referenced by dentry. - */ -int orangefs_setattr(struct dentry *dentry, struct iattr *iattr) +int __orangefs_setattr(struct inode *inode, struct iattr *iattr) { - struct inode *inode = dentry->d_inode; int ret; - gossip_debug(GOSSIP_INODE_DEBUG, - "%s: called on %pd\n", - __func__, - dentry); - - ret = setattr_prepare(dentry, iattr); - if (ret) - goto out; + if (iattr->ia_valid & ATTR_MODE) { + if (iattr->ia_mode & (S_ISVTX)) { + if (is_root_handle(inode)) { + /* + * allow sticky bit to be set on root (since + * it shows up that way by default anyhow), + * but don't show it to the server + */ + iattr->ia_mode -= S_ISVTX; + } else { + gossip_debug(GOSSIP_UTILS_DEBUG, + "User attempted to set sticky bit on non-root directory; returning EINVAL.\n"); + return -EINVAL; + } + } + if (iattr->ia_mode & (S_ISUID)) { + gossip_debug(GOSSIP_UTILS_DEBUG, + "Attempting to set setuid bit (not supported); returning EINVAL.\n"); + return -EINVAL; + } + } if (iattr->ia_valid & ATTR_SIZE) { ret = orangefs_setattr_size(inode, iattr); @@ -225,7 +235,24 @@ int orangefs_setattr(struct dentry *dentry, struct iattr *iattr) goto out; } +again: + spin_lock(&inode->i_lock); + if (ORANGEFS_I(inode)->attr_valid) { + if (uid_eq(ORANGEFS_I(inode)->attr_uid, current_fsuid()) && + gid_eq(ORANGEFS_I(inode)->attr_gid, current_fsgid())) { + ORANGEFS_I(inode)->attr_valid = iattr->ia_valid; + } else { + spin_unlock(&inode->i_lock); + write_inode_now(inode, 1); + goto again; + } + } else { + ORANGEFS_I(inode)->attr_valid = iattr->ia_valid; + ORANGEFS_I(inode)->attr_uid = current_fsuid(); + ORANGEFS_I(inode)->attr_gid = current_fsgid(); + } setattr_copy(inode, iattr); + spin_unlock(&inode->i_lock); mark_inode_dirty(inode); if (iattr->ia_valid & ATTR_MODE) @@ -234,7 +261,25 @@ int orangefs_setattr(struct dentry *dentry, struct iattr *iattr) ret = 0; out: - gossip_debug(GOSSIP_INODE_DEBUG, "%s: ret:%d:\n", __func__, ret); + return ret; +} + +/* + * Change attributes of an object referenced by dentry. + */ +int orangefs_setattr(struct dentry *dentry, struct iattr *iattr) +{ + int ret; + gossip_debug(GOSSIP_INODE_DEBUG, "__orangefs_setattr: called on %pd\n", + dentry); + ret = setattr_prepare(dentry, iattr); + if (ret) + goto out; + ret = __orangefs_setattr(d_inode(dentry), iattr); + sync_inode_metadata(d_inode(dentry), 1); +out: + gossip_debug(GOSSIP_INODE_DEBUG, "orangefs_setattr: returning %d\n", + ret); return ret; } @@ -300,7 +345,7 @@ int orangefs_update_time(struct inode *inode, struct timespec64 *time, int flags iattr.ia_valid |= ATTR_CTIME; if (flags & S_MTIME) iattr.ia_valid |= ATTR_MTIME; - return orangefs_inode_setattr(inode, &iattr); + return __orangefs_setattr(inode, &iattr); } /* ORANGEFS2 implementation of VFS inode operations for files */ @@ -360,6 +405,7 @@ static int orangefs_set_inode(struct inode *inode, void *data) struct orangefs_object_kref *ref = (struct orangefs_object_kref *) data; ORANGEFS_I(inode)->refn.fs_id = ref->fs_id; ORANGEFS_I(inode)->refn.khandle = ref->khandle; + ORANGEFS_I(inode)->attr_valid = 0; hash_init(ORANGEFS_I(inode)->xattr_cache); return 0; } |