.. | .. |
---|
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 | */ |
---|
.. | .. |
---|
135 | 136 | * NOTE: in kernel land, we never use the sys_attr->link_target for |
---|
136 | 137 | * anything, so don't bother copying it into the sys_attr object here. |
---|
137 | 138 | */ |
---|
138 | | -static inline int copy_attributes_from_inode(struct inode *inode, |
---|
139 | | - struct ORANGEFS_sys_attr_s *attrs, |
---|
140 | | - struct iattr *iattr) |
---|
| 139 | +static inline void copy_attributes_from_inode(struct inode *inode, |
---|
| 140 | + struct ORANGEFS_sys_attr_s *attrs) |
---|
141 | 141 | { |
---|
142 | | - umode_t tmp_mode; |
---|
143 | | - |
---|
144 | | - if (!iattr || !inode || !attrs) { |
---|
145 | | - gossip_err("NULL iattr (%p), inode (%p), attrs (%p) " |
---|
146 | | - "in copy_attributes_from_inode!\n", |
---|
147 | | - iattr, |
---|
148 | | - inode, |
---|
149 | | - attrs); |
---|
150 | | - return -EINVAL; |
---|
151 | | - } |
---|
152 | | - /* |
---|
153 | | - * We need to be careful to only copy the attributes out of the |
---|
154 | | - * iattr object that we know are valid. |
---|
155 | | - */ |
---|
| 142 | + struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); |
---|
156 | 143 | attrs->mask = 0; |
---|
157 | | - if (iattr->ia_valid & ATTR_UID) { |
---|
158 | | - 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); |
---|
159 | 146 | attrs->mask |= ORANGEFS_ATTR_SYS_UID; |
---|
160 | 147 | gossip_debug(GOSSIP_UTILS_DEBUG, "(UID) %d\n", attrs->owner); |
---|
161 | 148 | } |
---|
162 | | - if (iattr->ia_valid & ATTR_GID) { |
---|
163 | | - 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); |
---|
164 | 151 | attrs->mask |= ORANGEFS_ATTR_SYS_GID; |
---|
165 | 152 | gossip_debug(GOSSIP_UTILS_DEBUG, "(GID) %d\n", attrs->group); |
---|
166 | 153 | } |
---|
167 | 154 | |
---|
168 | | - if (iattr->ia_valid & ATTR_ATIME) { |
---|
| 155 | + if (orangefs_inode->attr_valid & ATTR_ATIME) { |
---|
169 | 156 | attrs->mask |= ORANGEFS_ATTR_SYS_ATIME; |
---|
170 | | - if (iattr->ia_valid & ATTR_ATIME_SET) { |
---|
171 | | - 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; |
---|
172 | 159 | attrs->mask |= ORANGEFS_ATTR_SYS_ATIME_SET; |
---|
173 | 160 | } |
---|
174 | 161 | } |
---|
175 | | - if (iattr->ia_valid & ATTR_MTIME) { |
---|
| 162 | + if (orangefs_inode->attr_valid & ATTR_MTIME) { |
---|
176 | 163 | attrs->mask |= ORANGEFS_ATTR_SYS_MTIME; |
---|
177 | | - if (iattr->ia_valid & ATTR_MTIME_SET) { |
---|
178 | | - 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; |
---|
179 | 166 | attrs->mask |= ORANGEFS_ATTR_SYS_MTIME_SET; |
---|
180 | 167 | } |
---|
181 | 168 | } |
---|
182 | | - if (iattr->ia_valid & ATTR_CTIME) |
---|
| 169 | + if (orangefs_inode->attr_valid & ATTR_CTIME) |
---|
183 | 170 | attrs->mask |= ORANGEFS_ATTR_SYS_CTIME; |
---|
184 | 171 | |
---|
185 | 172 | /* |
---|
.. | .. |
---|
188 | 175 | * worry about ATTR_SIZE |
---|
189 | 176 | */ |
---|
190 | 177 | |
---|
191 | | - if (iattr->ia_valid & ATTR_MODE) { |
---|
192 | | - tmp_mode = iattr->ia_mode; |
---|
193 | | - if (tmp_mode & (S_ISVTX)) { |
---|
194 | | - if (is_root_handle(inode)) { |
---|
195 | | - /* |
---|
196 | | - * allow sticky bit to be set on root (since |
---|
197 | | - * it shows up that way by default anyhow), |
---|
198 | | - * but don't show it to the server |
---|
199 | | - */ |
---|
200 | | - tmp_mode -= S_ISVTX; |
---|
201 | | - } else { |
---|
202 | | - gossip_debug(GOSSIP_UTILS_DEBUG, |
---|
203 | | - "%s: setting sticky bit not supported.\n", |
---|
204 | | - __func__); |
---|
205 | | - return -EINVAL; |
---|
206 | | - } |
---|
207 | | - } |
---|
208 | | - |
---|
209 | | - if (tmp_mode & (S_ISUID)) { |
---|
210 | | - gossip_debug(GOSSIP_UTILS_DEBUG, |
---|
211 | | - "%s: setting setuid bit not supported.\n", |
---|
212 | | - __func__); |
---|
213 | | - return -EINVAL; |
---|
214 | | - } |
---|
215 | | - |
---|
216 | | - attrs->perms = ORANGEFS_util_translate_mode(tmp_mode); |
---|
| 178 | + if (orangefs_inode->attr_valid & ATTR_MODE) { |
---|
| 179 | + attrs->perms = ORANGEFS_util_translate_mode(inode->i_mode); |
---|
217 | 180 | attrs->mask |= ORANGEFS_ATTR_SYS_PERM; |
---|
218 | 181 | } |
---|
219 | | - |
---|
220 | | - return 0; |
---|
221 | 182 | } |
---|
222 | 183 | |
---|
223 | 184 | static int orangefs_inode_type(enum orangefs_ds_type objtype) |
---|
.. | .. |
---|
272 | 233 | return 0; |
---|
273 | 234 | } |
---|
274 | 235 | |
---|
275 | | -int orangefs_inode_getattr(struct inode *inode, int new, int bypass, |
---|
276 | | - u32 request_mask) |
---|
| 236 | +int orangefs_inode_getattr(struct inode *inode, int flags) |
---|
277 | 237 | { |
---|
278 | 238 | struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); |
---|
279 | 239 | struct orangefs_kernel_op_s *new_op; |
---|
280 | 240 | loff_t inode_size; |
---|
281 | 241 | int ret, type; |
---|
282 | 242 | |
---|
283 | | - gossip_debug(GOSSIP_UTILS_DEBUG, "%s: called on inode %pU\n", __func__, |
---|
284 | | - get_khandle_from_ino(inode)); |
---|
| 243 | + gossip_debug(GOSSIP_UTILS_DEBUG, "%s: called on inode %pU flags %d\n", |
---|
| 244 | + __func__, get_khandle_from_ino(inode), flags); |
---|
285 | 245 | |
---|
286 | | - if (!new && !bypass) { |
---|
287 | | - /* |
---|
288 | | - * Must have all the attributes in the mask and be within cache |
---|
289 | | - * time. |
---|
290 | | - */ |
---|
291 | | - if ((request_mask & orangefs_inode->getattr_mask) == |
---|
292 | | - request_mask && |
---|
293 | | - time_before(jiffies, orangefs_inode->getattr_time)) |
---|
294 | | - return 0; |
---|
| 246 | +again: |
---|
| 247 | + spin_lock(&inode->i_lock); |
---|
| 248 | + /* Must have all the attributes in the mask and be within cache time. */ |
---|
| 249 | + if ((!flags && time_before(jiffies, orangefs_inode->getattr_time)) || |
---|
| 250 | + orangefs_inode->attr_valid || inode->i_state & I_DIRTY_PAGES) { |
---|
| 251 | + if (orangefs_inode->attr_valid) { |
---|
| 252 | + spin_unlock(&inode->i_lock); |
---|
| 253 | + write_inode_now(inode, 1); |
---|
| 254 | + goto again; |
---|
| 255 | + } |
---|
| 256 | + spin_unlock(&inode->i_lock); |
---|
| 257 | + return 0; |
---|
295 | 258 | } |
---|
| 259 | + spin_unlock(&inode->i_lock); |
---|
296 | 260 | |
---|
297 | 261 | new_op = op_alloc(ORANGEFS_VFS_OP_GETATTR); |
---|
298 | 262 | if (!new_op) |
---|
.. | .. |
---|
302 | 266 | * Size is the hardest attribute to get. The incremental cost of any |
---|
303 | 267 | * other attribute is essentially zero. |
---|
304 | 268 | */ |
---|
305 | | - if (request_mask & STATX_SIZE || new) |
---|
| 269 | + if (flags) |
---|
306 | 270 | new_op->upcall.req.getattr.mask = ORANGEFS_ATTR_SYS_ALL_NOHINT; |
---|
307 | 271 | else |
---|
308 | 272 | new_op->upcall.req.getattr.mask = |
---|
.. | .. |
---|
313 | 277 | if (ret != 0) |
---|
314 | 278 | goto out; |
---|
315 | 279 | |
---|
316 | | - if (!new) { |
---|
| 280 | +again2: |
---|
| 281 | + spin_lock(&inode->i_lock); |
---|
| 282 | + /* Must have all the attributes in the mask and be within cache time. */ |
---|
| 283 | + if ((!flags && time_before(jiffies, orangefs_inode->getattr_time)) || |
---|
| 284 | + orangefs_inode->attr_valid || inode->i_state & I_DIRTY_PAGES) { |
---|
| 285 | + if (orangefs_inode->attr_valid) { |
---|
| 286 | + spin_unlock(&inode->i_lock); |
---|
| 287 | + write_inode_now(inode, 1); |
---|
| 288 | + goto again2; |
---|
| 289 | + } |
---|
| 290 | + if (inode->i_state & I_DIRTY_PAGES) { |
---|
| 291 | + ret = 0; |
---|
| 292 | + goto out_unlock; |
---|
| 293 | + } |
---|
| 294 | + gossip_debug(GOSSIP_UTILS_DEBUG, "%s: in cache or dirty\n", |
---|
| 295 | + __func__); |
---|
| 296 | + ret = 0; |
---|
| 297 | + goto out_unlock; |
---|
| 298 | + } |
---|
| 299 | + |
---|
| 300 | + if (!(flags & ORANGEFS_GETATTR_NEW)) { |
---|
317 | 301 | ret = orangefs_inode_is_stale(inode, |
---|
318 | 302 | &new_op->downcall.resp.getattr.attributes, |
---|
319 | 303 | new_op->downcall.resp.getattr.link_target); |
---|
320 | 304 | if (ret) { |
---|
321 | 305 | ret = -ESTALE; |
---|
322 | | - goto out; |
---|
| 306 | + goto out_unlock; |
---|
323 | 307 | } |
---|
324 | 308 | } |
---|
325 | 309 | |
---|
.. | .. |
---|
329 | 313 | case S_IFREG: |
---|
330 | 314 | inode->i_flags = orangefs_inode_flags(&new_op-> |
---|
331 | 315 | downcall.resp.getattr.attributes); |
---|
332 | | - if (request_mask & STATX_SIZE || new) { |
---|
| 316 | + if (flags) { |
---|
333 | 317 | inode_size = (loff_t)new_op-> |
---|
334 | 318 | downcall.resp.getattr.attributes.size; |
---|
335 | 319 | inode->i_size = inode_size; |
---|
336 | 320 | inode->i_blkbits = ffs(new_op->downcall.resp.getattr. |
---|
337 | 321 | attributes.blksize); |
---|
338 | | - spin_lock(&inode->i_lock); |
---|
339 | 322 | inode->i_bytes = inode_size; |
---|
340 | 323 | inode->i_blocks = |
---|
341 | 324 | (inode_size + 512 - inode_size % 512)/512; |
---|
342 | | - spin_unlock(&inode->i_lock); |
---|
343 | 325 | } |
---|
344 | 326 | break; |
---|
345 | 327 | case S_IFDIR: |
---|
346 | | - if (request_mask & STATX_SIZE || new) { |
---|
| 328 | + if (flags) { |
---|
347 | 329 | inode->i_size = PAGE_SIZE; |
---|
348 | | - spin_lock(&inode->i_lock); |
---|
349 | 330 | inode_set_bytes(inode, inode->i_size); |
---|
350 | | - spin_unlock(&inode->i_lock); |
---|
351 | 331 | } |
---|
352 | 332 | set_nlink(inode, 1); |
---|
353 | 333 | break; |
---|
354 | 334 | case S_IFLNK: |
---|
355 | | - if (new) { |
---|
| 335 | + if (flags & ORANGEFS_GETATTR_NEW) { |
---|
356 | 336 | inode->i_size = (loff_t)strlen(new_op-> |
---|
357 | 337 | downcall.resp.getattr.link_target); |
---|
358 | 338 | ret = strscpy(orangefs_inode->link_target, |
---|
.. | .. |
---|
360 | 340 | ORANGEFS_NAME_MAX); |
---|
361 | 341 | if (ret == -E2BIG) { |
---|
362 | 342 | ret = -EIO; |
---|
363 | | - goto out; |
---|
| 343 | + goto out_unlock; |
---|
364 | 344 | } |
---|
365 | 345 | inode->i_link = orangefs_inode->link_target; |
---|
366 | 346 | } |
---|
.. | .. |
---|
370 | 350 | /* XXX: ESTALE? This is what is done if it is not new. */ |
---|
371 | 351 | orangefs_make_bad_inode(inode); |
---|
372 | 352 | ret = -ESTALE; |
---|
373 | | - goto out; |
---|
| 353 | + goto out_unlock; |
---|
374 | 354 | } |
---|
375 | 355 | |
---|
376 | 356 | inode->i_uid = make_kuid(&init_user_ns, new_op-> |
---|
.. | .. |
---|
393 | 373 | |
---|
394 | 374 | orangefs_inode->getattr_time = jiffies + |
---|
395 | 375 | orangefs_getattr_timeout_msecs*HZ/1000; |
---|
396 | | - if (request_mask & STATX_SIZE || new) |
---|
397 | | - orangefs_inode->getattr_mask = STATX_BASIC_STATS; |
---|
398 | | - else |
---|
399 | | - orangefs_inode->getattr_mask = STATX_BASIC_STATS & ~STATX_SIZE; |
---|
400 | 376 | ret = 0; |
---|
| 377 | +out_unlock: |
---|
| 378 | + spin_unlock(&inode->i_lock); |
---|
401 | 379 | out: |
---|
402 | 380 | op_release(new_op); |
---|
403 | 381 | return ret; |
---|
.. | .. |
---|
436 | 414 | * issues a orangefs setattr request to make sure the new attribute values |
---|
437 | 415 | * take effect if successful. returns 0 on success; -errno otherwise |
---|
438 | 416 | */ |
---|
439 | | -int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr) |
---|
| 417 | +int orangefs_inode_setattr(struct inode *inode) |
---|
440 | 418 | { |
---|
441 | 419 | struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); |
---|
442 | 420 | struct orangefs_kernel_op_s *new_op; |
---|
.. | .. |
---|
446 | 424 | if (!new_op) |
---|
447 | 425 | return -ENOMEM; |
---|
448 | 426 | |
---|
| 427 | + spin_lock(&inode->i_lock); |
---|
| 428 | + new_op->upcall.uid = from_kuid(&init_user_ns, orangefs_inode->attr_uid); |
---|
| 429 | + new_op->upcall.gid = from_kgid(&init_user_ns, orangefs_inode->attr_gid); |
---|
449 | 430 | new_op->upcall.req.setattr.refn = orangefs_inode->refn; |
---|
450 | | - ret = copy_attributes_from_inode(inode, |
---|
451 | | - &new_op->upcall.req.setattr.attributes, |
---|
452 | | - iattr); |
---|
453 | | - if (ret >= 0) { |
---|
454 | | - ret = service_operation(new_op, __func__, |
---|
455 | | - get_interruptible_flag(inode)); |
---|
456 | | - |
---|
457 | | - gossip_debug(GOSSIP_UTILS_DEBUG, |
---|
458 | | - "orangefs_inode_setattr: returning %d\n", |
---|
459 | | - ret); |
---|
| 431 | + copy_attributes_from_inode(inode, |
---|
| 432 | + &new_op->upcall.req.setattr.attributes); |
---|
| 433 | + orangefs_inode->attr_valid = 0; |
---|
| 434 | + if (!new_op->upcall.req.setattr.attributes.mask) { |
---|
| 435 | + spin_unlock(&inode->i_lock); |
---|
| 436 | + op_release(new_op); |
---|
| 437 | + return 0; |
---|
460 | 438 | } |
---|
| 439 | + spin_unlock(&inode->i_lock); |
---|
| 440 | + |
---|
| 441 | + ret = service_operation(new_op, __func__, |
---|
| 442 | + get_interruptible_flag(inode) | ORANGEFS_OP_WRITEBACK); |
---|
| 443 | + gossip_debug(GOSSIP_UTILS_DEBUG, |
---|
| 444 | + "orangefs_inode_setattr: returning %d\n", ret); |
---|
| 445 | + if (ret) |
---|
| 446 | + orangefs_make_bad_inode(inode); |
---|
461 | 447 | |
---|
462 | 448 | op_release(new_op); |
---|
463 | 449 | |
---|
464 | 450 | if (ret == 0) |
---|
465 | 451 | orangefs_inode->getattr_time = jiffies - 1; |
---|
466 | | - |
---|
467 | 452 | return ret; |
---|
468 | 453 | } |
---|
469 | 454 | |
---|