Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Martin Brandenburg and committed by
Mike Marshall
afd9fb2a df2d7337

+129 -119
+2 -2
fs/orangefs/acl.c
··· 142 142 rc = __orangefs_set_acl(inode, acl, type); 143 143 } else { 144 144 iattr.ia_valid = ATTR_MODE; 145 - rc = orangefs_inode_setattr(inode, &iattr); 145 + rc = __orangefs_setattr(inode, &iattr); 146 146 } 147 147 148 148 return rc; ··· 185 185 inode->i_mode = mode; 186 186 iattr.ia_mode = mode; 187 187 iattr.ia_valid |= ATTR_MODE; 188 - orangefs_inode_setattr(inode, &iattr); 188 + __orangefs_setattr(inode, &iattr); 189 189 } 190 190 191 191 return error;
+61 -15
fs/orangefs/inode.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 /* 3 3 * (C) 2001 Clemson University and The University of Chicago 4 + * Copyright 2018 Omnibond Systems, L.L.C. 4 5 * 5 6 * See COPYING in top-level directory. 6 7 */ ··· 203 202 return ret; 204 203 } 205 204 206 - /* 207 - * Change attributes of an object referenced by dentry. 208 - */ 209 - int orangefs_setattr(struct dentry *dentry, struct iattr *iattr) 205 + int __orangefs_setattr(struct inode *inode, struct iattr *iattr) 210 206 { 211 - struct inode *inode = dentry->d_inode; 212 207 int ret; 213 208 214 - gossip_debug(GOSSIP_INODE_DEBUG, 215 - "%s: called on %pd\n", 216 - __func__, 217 - dentry); 218 - 219 - ret = setattr_prepare(dentry, iattr); 220 - if (ret) 221 - goto out; 209 + if (iattr->ia_valid & ATTR_MODE) { 210 + if (iattr->ia_mode & (S_ISVTX)) { 211 + if (is_root_handle(inode)) { 212 + /* 213 + * allow sticky bit to be set on root (since 214 + * it shows up that way by default anyhow), 215 + * but don't show it to the server 216 + */ 217 + iattr->ia_mode -= S_ISVTX; 218 + } else { 219 + gossip_debug(GOSSIP_UTILS_DEBUG, 220 + "User attempted to set sticky bit on non-root directory; returning EINVAL.\n"); 221 + return -EINVAL; 222 + } 223 + } 224 + if (iattr->ia_mode & (S_ISUID)) { 225 + gossip_debug(GOSSIP_UTILS_DEBUG, 226 + "Attempting to set setuid bit (not supported); returning EINVAL.\n"); 227 + return -EINVAL; 228 + } 229 + } 222 230 223 231 if (iattr->ia_valid & ATTR_SIZE) { 224 232 ret = orangefs_setattr_size(inode, iattr); ··· 235 225 goto out; 236 226 } 237 227 228 + again: 229 + spin_lock(&inode->i_lock); 230 + if (ORANGEFS_I(inode)->attr_valid) { 231 + if (uid_eq(ORANGEFS_I(inode)->attr_uid, current_fsuid()) && 232 + gid_eq(ORANGEFS_I(inode)->attr_gid, current_fsgid())) { 233 + ORANGEFS_I(inode)->attr_valid = iattr->ia_valid; 234 + } else { 235 + spin_unlock(&inode->i_lock); 236 + write_inode_now(inode, 1); 237 + goto again; 238 + } 239 + } else { 240 + ORANGEFS_I(inode)->attr_valid = iattr->ia_valid; 241 + ORANGEFS_I(inode)->attr_uid = current_fsuid(); 242 + ORANGEFS_I(inode)->attr_gid = current_fsgid(); 243 + } 238 244 setattr_copy(inode, iattr); 245 + spin_unlock(&inode->i_lock); 239 246 mark_inode_dirty(inode); 240 247 241 248 if (iattr->ia_valid & ATTR_MODE) ··· 261 234 262 235 ret = 0; 263 236 out: 264 - gossip_debug(GOSSIP_INODE_DEBUG, "%s: ret:%d:\n", __func__, ret); 237 + return ret; 238 + } 239 + 240 + /* 241 + * Change attributes of an object referenced by dentry. 242 + */ 243 + int orangefs_setattr(struct dentry *dentry, struct iattr *iattr) 244 + { 245 + int ret; 246 + gossip_debug(GOSSIP_INODE_DEBUG, "__orangefs_setattr: called on %pd\n", 247 + dentry); 248 + ret = setattr_prepare(dentry, iattr); 249 + if (ret) 250 + goto out; 251 + ret = __orangefs_setattr(d_inode(dentry), iattr); 252 + sync_inode_metadata(d_inode(dentry), 1); 253 + out: 254 + gossip_debug(GOSSIP_INODE_DEBUG, "orangefs_setattr: returning %d\n", 255 + ret); 265 256 return ret; 266 257 } 267 258 ··· 345 300 iattr.ia_valid |= ATTR_CTIME; 346 301 if (flags & S_MTIME) 347 302 iattr.ia_valid |= ATTR_MTIME; 348 - return orangefs_inode_setattr(inode, &iattr); 303 + return __orangefs_setattr(inode, &iattr); 349 304 } 350 305 351 306 /* ORANGEFS2 implementation of VFS inode operations for files */ ··· 405 360 struct orangefs_object_kref *ref = (struct orangefs_object_kref *) data; 406 361 ORANGEFS_I(inode)->refn.fs_id = ref->fs_id; 407 362 ORANGEFS_I(inode)->refn.khandle = ref->khandle; 363 + ORANGEFS_I(inode)->attr_valid = 0; 408 364 hash_init(ORANGEFS_I(inode)->xattr_cache); 409 365 return 0; 410 366 }
+15 -20
fs/orangefs/namei.c
··· 82 82 __func__, 83 83 dentry); 84 84 85 - dir->i_mtime = dir->i_ctime = current_time(dir); 86 85 memset(&iattr, 0, sizeof iattr); 87 - iattr.ia_valid |= ATTR_MTIME; 88 - orangefs_inode_setattr(dir, &iattr); 89 - mark_inode_dirty_sync(dir); 86 + iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME; 87 + iattr.ia_mtime = iattr.ia_ctime = current_time(dir); 88 + __orangefs_setattr(dir, &iattr); 90 89 ret = 0; 91 90 out: 92 91 op_release(new_op); ··· 207 208 if (!ret) { 208 209 drop_nlink(inode); 209 210 210 - dir->i_mtime = dir->i_ctime = current_time(dir); 211 211 memset(&iattr, 0, sizeof iattr); 212 - iattr.ia_valid |= ATTR_MTIME; 213 - orangefs_inode_setattr(dir, &iattr); 214 - mark_inode_dirty_sync(dir); 212 + iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME; 213 + iattr.ia_mtime = iattr.ia_ctime = current_time(dir); 214 + __orangefs_setattr(dir, &iattr); 215 215 } 216 216 return ret; 217 217 } ··· 293 295 get_khandle_from_ino(inode), 294 296 dentry); 295 297 296 - dir->i_mtime = dir->i_ctime = current_time(dir); 297 298 memset(&iattr, 0, sizeof iattr); 298 - iattr.ia_valid |= ATTR_MTIME; 299 - orangefs_inode_setattr(dir, &iattr); 300 - mark_inode_dirty_sync(dir); 299 + iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME; 300 + iattr.ia_mtime = iattr.ia_ctime = current_time(dir); 301 + __orangefs_setattr(dir, &iattr); 301 302 ret = 0; 302 303 out: 303 304 op_release(new_op); ··· 363 366 * NOTE: we have no good way to keep nlink consistent for directories 364 367 * across clients; keep constant at 1. 365 368 */ 366 - dir->i_mtime = dir->i_ctime = current_time(dir); 367 369 memset(&iattr, 0, sizeof iattr); 368 - iattr.ia_valid |= ATTR_MTIME; 369 - orangefs_inode_setattr(dir, &iattr); 370 - mark_inode_dirty_sync(dir); 370 + iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME; 371 + iattr.ia_mtime = iattr.ia_ctime = current_time(dir); 372 + __orangefs_setattr(dir, &iattr); 371 373 out: 372 374 op_release(new_op); 373 375 return ret; ··· 389 393 "orangefs_rename: called (%pd2 => %pd2) ct=%d\n", 390 394 old_dentry, new_dentry, d_count(new_dentry)); 391 395 392 - new_dir->i_mtime = new_dir->i_ctime = current_time(new_dir); 393 396 memset(&iattr, 0, sizeof iattr); 394 - iattr.ia_valid |= ATTR_MTIME; 395 - orangefs_inode_setattr(new_dir, &iattr); 396 - mark_inode_dirty_sync(new_dir); 397 + iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME; 398 + iattr.ia_mtime = iattr.ia_ctime = current_time(new_dir); 399 + __orangefs_setattr(new_dir, &iattr); 397 400 398 401 new_op = op_alloc(ORANGEFS_VFS_OP_RENAME); 399 402 if (!new_op)
+6 -2
fs/orangefs/orangefs-kernel.h
··· 193 193 sector_t last_failed_block_index_read; 194 194 195 195 unsigned long getattr_time; 196 + int attr_valid; 197 + kuid_t attr_uid; 198 + kgid_t attr_gid; 196 199 197 200 DECLARE_HASHTABLE(xattr_cache, 4); 198 201 }; ··· 348 345 dev_t dev, 349 346 struct orangefs_object_kref *ref); 350 347 351 - int orangefs_setattr(struct dentry *dentry, struct iattr *iattr); 348 + int __orangefs_setattr(struct inode *, struct iattr *); 349 + int orangefs_setattr(struct dentry *, struct iattr *); 352 350 353 351 int orangefs_getattr(const struct path *path, struct kstat *stat, 354 352 u32 request_mask, unsigned int flags); ··· 407 403 408 404 int orangefs_inode_check_changed(struct inode *inode); 409 405 410 - int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr); 406 + int orangefs_inode_setattr(struct inode *inode); 411 407 412 408 bool orangefs_cancel_op_in_progress(struct orangefs_kernel_op_s *op); 413 409
+44 -70
fs/orangefs/orangefs-utils.c
··· 136 136 * NOTE: in kernel land, we never use the sys_attr->link_target for 137 137 * anything, so don't bother copying it into the sys_attr object here. 138 138 */ 139 - static inline int copy_attributes_from_inode(struct inode *inode, 140 - struct ORANGEFS_sys_attr_s *attrs, 141 - struct iattr *iattr) 139 + static inline void copy_attributes_from_inode(struct inode *inode, 140 + struct ORANGEFS_sys_attr_s *attrs) 142 141 { 143 - umode_t tmp_mode; 144 - 145 - if (!iattr || !inode || !attrs) { 146 - gossip_err("NULL iattr (%p), inode (%p), attrs (%p) " 147 - "in copy_attributes_from_inode!\n", 148 - iattr, 149 - inode, 150 - attrs); 151 - return -EINVAL; 152 - } 153 - /* 154 - * We need to be careful to only copy the attributes out of the 155 - * iattr object that we know are valid. 156 - */ 142 + struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 157 143 attrs->mask = 0; 158 - if (iattr->ia_valid & ATTR_UID) { 159 - attrs->owner = from_kuid(&init_user_ns, iattr->ia_uid); 144 + if (orangefs_inode->attr_valid & ATTR_UID) { 145 + attrs->owner = from_kuid(&init_user_ns, inode->i_uid); 160 146 attrs->mask |= ORANGEFS_ATTR_SYS_UID; 161 147 gossip_debug(GOSSIP_UTILS_DEBUG, "(UID) %d\n", attrs->owner); 162 148 } 163 - if (iattr->ia_valid & ATTR_GID) { 164 - attrs->group = from_kgid(&init_user_ns, iattr->ia_gid); 149 + if (orangefs_inode->attr_valid & ATTR_GID) { 150 + attrs->group = from_kgid(&init_user_ns, inode->i_gid); 165 151 attrs->mask |= ORANGEFS_ATTR_SYS_GID; 166 152 gossip_debug(GOSSIP_UTILS_DEBUG, "(GID) %d\n", attrs->group); 167 153 } 168 154 169 - if (iattr->ia_valid & ATTR_ATIME) { 155 + if (orangefs_inode->attr_valid & ATTR_ATIME) { 170 156 attrs->mask |= ORANGEFS_ATTR_SYS_ATIME; 171 - if (iattr->ia_valid & ATTR_ATIME_SET) { 172 - attrs->atime = (time64_t)iattr->ia_atime.tv_sec; 157 + if (orangefs_inode->attr_valid & ATTR_ATIME_SET) { 158 + attrs->atime = (time64_t)inode->i_atime.tv_sec; 173 159 attrs->mask |= ORANGEFS_ATTR_SYS_ATIME_SET; 174 160 } 175 161 } 176 - if (iattr->ia_valid & ATTR_MTIME) { 162 + if (orangefs_inode->attr_valid & ATTR_MTIME) { 177 163 attrs->mask |= ORANGEFS_ATTR_SYS_MTIME; 178 - if (iattr->ia_valid & ATTR_MTIME_SET) { 179 - attrs->mtime = (time64_t)iattr->ia_mtime.tv_sec; 164 + if (orangefs_inode->attr_valid & ATTR_MTIME_SET) { 165 + attrs->mtime = (time64_t)inode->i_mtime.tv_sec; 180 166 attrs->mask |= ORANGEFS_ATTR_SYS_MTIME_SET; 181 167 } 182 168 } 183 - if (iattr->ia_valid & ATTR_CTIME) 169 + if (orangefs_inode->attr_valid & ATTR_CTIME) 184 170 attrs->mask |= ORANGEFS_ATTR_SYS_CTIME; 185 171 186 172 /* ··· 175 189 * worry about ATTR_SIZE 176 190 */ 177 191 178 - if (iattr->ia_valid & ATTR_MODE) { 179 - tmp_mode = iattr->ia_mode; 180 - if (tmp_mode & (S_ISVTX)) { 181 - if (is_root_handle(inode)) { 182 - /* 183 - * allow sticky bit to be set on root (since 184 - * it shows up that way by default anyhow), 185 - * but don't show it to the server 186 - */ 187 - tmp_mode -= S_ISVTX; 188 - } else { 189 - gossip_debug(GOSSIP_UTILS_DEBUG, 190 - "%s: setting sticky bit not supported.\n", 191 - __func__); 192 - return -EINVAL; 193 - } 194 - } 195 - 196 - if (tmp_mode & (S_ISUID)) { 197 - gossip_debug(GOSSIP_UTILS_DEBUG, 198 - "%s: setting setuid bit not supported.\n", 199 - __func__); 200 - return -EINVAL; 201 - } 202 - 203 - attrs->perms = ORANGEFS_util_translate_mode(tmp_mode); 192 + if (orangefs_inode->attr_valid & ATTR_MODE) { 193 + attrs->perms = ORANGEFS_util_translate_mode(inode->i_mode); 204 194 attrs->mask |= ORANGEFS_ATTR_SYS_PERM; 205 195 } 206 - 207 - return 0; 208 196 } 209 197 210 198 static int orangefs_inode_type(enum orangefs_ds_type objtype) ··· 243 283 gossip_debug(GOSSIP_UTILS_DEBUG, "%s: called on inode %pU flags %d\n", 244 284 __func__, get_khandle_from_ino(inode), flags); 245 285 286 + again: 246 287 spin_lock(&inode->i_lock); 247 288 /* Must have all the attributes in the mask and be within cache time. */ 248 289 if ((!flags && time_before(jiffies, orangefs_inode->getattr_time)) || 249 - inode->i_state & I_DIRTY) { 290 + orangefs_inode->attr_valid) { 291 + if (orangefs_inode->attr_valid) { 292 + spin_unlock(&inode->i_lock); 293 + write_inode_now(inode, 1); 294 + goto again; 295 + } 250 296 spin_unlock(&inode->i_lock); 251 297 return 0; 252 298 } ··· 277 311 if (ret != 0) 278 312 goto out; 279 313 314 + again2: 280 315 spin_lock(&inode->i_lock); 281 316 /* Must have all the attributes in the mask and be within cache time. */ 282 317 if ((!flags && time_before(jiffies, orangefs_inode->getattr_time)) || 283 - inode->i_state & I_DIRTY) { 318 + orangefs_inode->attr_valid) { 319 + if (orangefs_inode->attr_valid) { 320 + spin_unlock(&inode->i_lock); 321 + write_inode_now(inode, 1); 322 + goto again2; 323 + } 284 324 gossip_debug(GOSSIP_UTILS_DEBUG, "%s: in cache or dirty\n", 285 325 __func__); 286 326 ret = 0; ··· 410 438 * issues a orangefs setattr request to make sure the new attribute values 411 439 * take effect if successful. returns 0 on success; -errno otherwise 412 440 */ 413 - int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr) 441 + int orangefs_inode_setattr(struct inode *inode) 414 442 { 415 443 struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 416 444 struct orangefs_kernel_op_s *new_op; ··· 420 448 if (!new_op) 421 449 return -ENOMEM; 422 450 451 + spin_lock(&inode->i_lock); 452 + new_op->upcall.uid = from_kuid(&init_user_ns, orangefs_inode->attr_uid); 453 + new_op->upcall.gid = from_kgid(&init_user_ns, orangefs_inode->attr_gid); 423 454 new_op->upcall.req.setattr.refn = orangefs_inode->refn; 424 - ret = copy_attributes_from_inode(inode, 425 - &new_op->upcall.req.setattr.attributes, 426 - iattr); 427 - if (ret >= 0) { 428 - ret = service_operation(new_op, __func__, 429 - get_interruptible_flag(inode)); 455 + copy_attributes_from_inode(inode, 456 + &new_op->upcall.req.setattr.attributes); 457 + orangefs_inode->attr_valid = 0; 458 + spin_unlock(&inode->i_lock); 430 459 431 - gossip_debug(GOSSIP_UTILS_DEBUG, 432 - "orangefs_inode_setattr: returning %d\n", 433 - ret); 434 - } 460 + ret = service_operation(new_op, __func__, 461 + get_interruptible_flag(inode)); 462 + gossip_debug(GOSSIP_UTILS_DEBUG, 463 + "orangefs_inode_setattr: returning %d\n", ret); 464 + if (ret) 465 + orangefs_make_bad_inode(inode); 435 466 436 467 op_release(new_op); 437 468 438 469 if (ret == 0) 439 470 orangefs_inode->getattr_time = jiffies - 1; 440 - 441 471 return ret; 442 472 } 443 473
+1 -10
fs/orangefs/super.c
··· 155 155 static int orangefs_write_inode(struct inode *inode, 156 156 struct writeback_control *wbc) 157 157 { 158 - struct iattr iattr; 159 158 gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_write_inode\n"); 160 - iattr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_ATIME | 161 - ATTR_ATIME_SET | ATTR_MTIME | ATTR_MTIME_SET | ATTR_CTIME; 162 - iattr.ia_mode = inode->i_mode; 163 - iattr.ia_uid = inode->i_uid; 164 - iattr.ia_gid = inode->i_gid; 165 - iattr.ia_atime = inode->i_atime; 166 - iattr.ia_mtime = inode->i_mtime; 167 - iattr.ia_ctime = inode->i_ctime; 168 - return orangefs_inode_setattr(inode, &iattr); 159 + return orangefs_inode_setattr(inode); 169 160 } 170 161 171 162 /*