diff options
Diffstat (limited to 'fs/orangefs/orangefs-utils.c')
-rw-r--r-- | fs/orangefs/orangefs-utils.c | 367 |
1 files changed, 46 insertions, 321 deletions
diff --git a/fs/orangefs/orangefs-utils.c b/fs/orangefs/orangefs-utils.c index 59c51e2c5a71..6643a6a87fa1 100644 --- a/fs/orangefs/orangefs-utils.c +++ b/fs/orangefs/orangefs-utils.c | |||
@@ -129,141 +129,6 @@ static int orangefs_inode_perms(struct ORANGEFS_sys_attr_s *attrs) | |||
129 | return perm_mode; | 129 | return perm_mode; |
130 | } | 130 | } |
131 | 131 | ||
132 | /* NOTE: symname is ignored unless the inode is a sym link */ | ||
133 | static int copy_attributes_to_inode(struct inode *inode, | ||
134 | struct ORANGEFS_sys_attr_s *attrs, | ||
135 | char *symname) | ||
136 | { | ||
137 | int ret = -1; | ||
138 | struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); | ||
139 | loff_t inode_size = 0; | ||
140 | loff_t rounded_up_size = 0; | ||
141 | |||
142 | |||
143 | /* | ||
144 | * arbitrarily set the inode block size; FIXME: we need to | ||
145 | * resolve the difference between the reported inode blocksize | ||
146 | * and the PAGE_CACHE_SIZE, since our block count will always | ||
147 | * be wrong. | ||
148 | * | ||
149 | * For now, we're setting the block count to be the proper | ||
150 | * number assuming the block size is 512 bytes, and the size is | ||
151 | * rounded up to the nearest 4K. This is apparently required | ||
152 | * to get proper size reports from the 'du' shell utility. | ||
153 | * | ||
154 | * changing the inode->i_blkbits to something other than | ||
155 | * PAGE_CACHE_SHIFT breaks mmap/execution as we depend on that. | ||
156 | */ | ||
157 | gossip_debug(GOSSIP_UTILS_DEBUG, | ||
158 | "attrs->mask = %x (objtype = %s)\n", | ||
159 | attrs->mask, | ||
160 | attrs->objtype == ORANGEFS_TYPE_METAFILE ? "file" : | ||
161 | attrs->objtype == ORANGEFS_TYPE_DIRECTORY ? "directory" : | ||
162 | attrs->objtype == ORANGEFS_TYPE_SYMLINK ? "symlink" : | ||
163 | "invalid/unknown"); | ||
164 | |||
165 | switch (attrs->objtype) { | ||
166 | case ORANGEFS_TYPE_METAFILE: | ||
167 | inode->i_flags = orangefs_inode_flags(attrs); | ||
168 | if (attrs->mask & ORANGEFS_ATTR_SYS_SIZE) { | ||
169 | inode_size = (loff_t) attrs->size; | ||
170 | rounded_up_size = | ||
171 | (inode_size + (4096 - (inode_size % 4096))); | ||
172 | |||
173 | spin_lock(&inode->i_lock); | ||
174 | inode->i_bytes = inode_size; | ||
175 | inode->i_blocks = | ||
176 | (unsigned long)(rounded_up_size / 512); | ||
177 | spin_unlock(&inode->i_lock); | ||
178 | |||
179 | /* | ||
180 | * NOTE: make sure all the places we're called | ||
181 | * from have the inode->i_sem lock. We're fine | ||
182 | * in 99% of the cases since we're mostly | ||
183 | * called from a lookup. | ||
184 | */ | ||
185 | inode->i_size = inode_size; | ||
186 | } | ||
187 | break; | ||
188 | case ORANGEFS_TYPE_SYMLINK: | ||
189 | if (symname != NULL) { | ||
190 | inode->i_size = (loff_t) strlen(symname); | ||
191 | break; | ||
192 | } | ||
193 | /*FALLTHRU*/ | ||
194 | default: | ||
195 | inode->i_size = PAGE_CACHE_SIZE; | ||
196 | |||
197 | spin_lock(&inode->i_lock); | ||
198 | inode_set_bytes(inode, inode->i_size); | ||
199 | spin_unlock(&inode->i_lock); | ||
200 | break; | ||
201 | } | ||
202 | |||
203 | inode->i_uid = make_kuid(&init_user_ns, attrs->owner); | ||
204 | inode->i_gid = make_kgid(&init_user_ns, attrs->group); | ||
205 | inode->i_atime.tv_sec = (time64_t) attrs->atime; | ||
206 | inode->i_mtime.tv_sec = (time64_t) attrs->mtime; | ||
207 | inode->i_ctime.tv_sec = (time64_t) attrs->ctime; | ||
208 | inode->i_atime.tv_nsec = 0; | ||
209 | inode->i_mtime.tv_nsec = 0; | ||
210 | inode->i_ctime.tv_nsec = 0; | ||
211 | |||
212 | inode->i_mode = orangefs_inode_perms(attrs); | ||
213 | |||
214 | if (is_root_handle(inode)) { | ||
215 | /* special case: mark the root inode as sticky */ | ||
216 | inode->i_mode |= S_ISVTX; | ||
217 | gossip_debug(GOSSIP_UTILS_DEBUG, | ||
218 | "Marking inode %pU as sticky\n", | ||
219 | get_khandle_from_ino(inode)); | ||
220 | } | ||
221 | |||
222 | switch (attrs->objtype) { | ||
223 | case ORANGEFS_TYPE_METAFILE: | ||
224 | inode->i_mode |= S_IFREG; | ||
225 | ret = 0; | ||
226 | break; | ||
227 | case ORANGEFS_TYPE_DIRECTORY: | ||
228 | inode->i_mode |= S_IFDIR; | ||
229 | /* NOTE: we have no good way to keep nlink consistent | ||
230 | * for directories across clients; keep constant at 1. | ||
231 | * Why 1? If we go with 2, then find(1) gets confused | ||
232 | * and won't work properly withouth the -noleaf option | ||
233 | */ | ||
234 | set_nlink(inode, 1); | ||
235 | ret = 0; | ||
236 | break; | ||
237 | case ORANGEFS_TYPE_SYMLINK: | ||
238 | inode->i_mode |= S_IFLNK; | ||
239 | |||
240 | /* copy link target to inode private data */ | ||
241 | if (orangefs_inode && symname) { | ||
242 | strncpy(orangefs_inode->link_target, | ||
243 | symname, | ||
244 | ORANGEFS_NAME_MAX); | ||
245 | gossip_debug(GOSSIP_UTILS_DEBUG, | ||
246 | "Copied attr link target %s\n", | ||
247 | orangefs_inode->link_target); | ||
248 | } | ||
249 | gossip_debug(GOSSIP_UTILS_DEBUG, | ||
250 | "symlink mode %o\n", | ||
251 | inode->i_mode); | ||
252 | ret = 0; | ||
253 | break; | ||
254 | default: | ||
255 | gossip_err("orangefs: copy_attributes_to_inode: got invalid attribute type %x\n", | ||
256 | attrs->objtype); | ||
257 | } | ||
258 | |||
259 | gossip_debug(GOSSIP_UTILS_DEBUG, | ||
260 | "orangefs: copy_attributes_to_inode: setting i_mode to %o, i_size to %lu\n", | ||
261 | inode->i_mode, | ||
262 | (unsigned long)i_size_read(inode)); | ||
263 | |||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | /* | 132 | /* |
268 | * NOTE: in kernel land, we never use the sys_attr->link_target for | 133 | * NOTE: in kernel land, we never use the sys_attr->link_target for |
269 | * anything, so don't bother copying it into the sys_attr object here. | 134 | * 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, | |||
351 | return 0; | 216 | return 0; |
352 | } | 217 | } |
353 | 218 | ||
354 | static int compare_attributes_to_inode(struct inode *inode, | ||
355 | struct ORANGEFS_sys_attr_s *attrs, | ||
356 | char *symname, | ||
357 | int mask) | ||
358 | { | ||
359 | struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); | ||
360 | loff_t inode_size, rounded_up_size; | ||
361 | |||
362 | /* Much of what happens below relies on the type being around. */ | ||
363 | if (!(mask & ORANGEFS_ATTR_SYS_TYPE)) | ||
364 | return 0; | ||
365 | |||
366 | if (attrs->objtype == ORANGEFS_TYPE_METAFILE && | ||
367 | inode->i_flags != orangefs_inode_flags(attrs)) | ||
368 | return 0; | ||
369 | |||
370 | /* Compare file size. */ | ||
371 | |||
372 | switch (attrs->objtype) { | ||
373 | case ORANGEFS_TYPE_METAFILE: | ||
374 | if (mask & ORANGEFS_ATTR_SYS_SIZE) { | ||
375 | inode_size = attrs->size; | ||
376 | rounded_up_size = inode_size + | ||
377 | (4096 - (inode_size % 4096)); | ||
378 | if (inode->i_bytes != inode_size || | ||
379 | inode->i_blocks != rounded_up_size/512) | ||
380 | return 0; | ||
381 | } | ||
382 | break; | ||
383 | case ORANGEFS_TYPE_SYMLINK: | ||
384 | if (mask & ORANGEFS_ATTR_SYS_SIZE) | ||
385 | if (symname && strlen(symname) != inode->i_size) | ||
386 | return 0; | ||
387 | break; | ||
388 | default: | ||
389 | if (inode->i_size != PAGE_CACHE_SIZE && | ||
390 | inode_get_bytes(inode) != PAGE_CACHE_SIZE) | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | /* Compare general attributes. */ | ||
395 | |||
396 | if (mask & ORANGEFS_ATTR_SYS_UID && | ||
397 | !uid_eq(inode->i_uid, make_kuid(&init_user_ns, attrs->owner))) | ||
398 | return 0; | ||
399 | if (mask & ORANGEFS_ATTR_SYS_GID && | ||
400 | !gid_eq(inode->i_gid, make_kgid(&init_user_ns, attrs->group))) | ||
401 | return 0; | ||
402 | if (mask & ORANGEFS_ATTR_SYS_ATIME && | ||
403 | inode->i_atime.tv_sec != attrs->atime) | ||
404 | return 0; | ||
405 | if (mask & ORANGEFS_ATTR_SYS_MTIME && | ||
406 | inode->i_atime.tv_sec != attrs->mtime) | ||
407 | return 0; | ||
408 | if (mask & ORANGEFS_ATTR_SYS_CTIME && | ||
409 | inode->i_atime.tv_sec != attrs->ctime) | ||
410 | return 0; | ||
411 | if (inode->i_atime.tv_nsec != 0 || | ||
412 | inode->i_mtime.tv_nsec != 0 || | ||
413 | inode->i_ctime.tv_nsec != 0) | ||
414 | return 0; | ||
415 | |||
416 | if (mask & ORANGEFS_ATTR_SYS_PERM && | ||
417 | (inode->i_mode & ~(S_ISVTX|S_IFREG|S_IFDIR|S_IFLNK)) != | ||
418 | orangefs_inode_perms(attrs)) | ||
419 | return 0; | ||
420 | |||
421 | if (is_root_handle(inode)) | ||
422 | if (!(inode->i_mode & S_ISVTX)) | ||
423 | return 0; | ||
424 | |||
425 | /* Compare file type. */ | ||
426 | |||
427 | switch (attrs->objtype) { | ||
428 | case ORANGEFS_TYPE_METAFILE: | ||
429 | if (!S_ISREG(inode->i_mode)) | ||
430 | return 0; | ||
431 | break; | ||
432 | case ORANGEFS_TYPE_DIRECTORY: | ||
433 | if (!S_ISDIR(inode->i_mode)) | ||
434 | return 0; | ||
435 | if (inode->i_nlink != 1) | ||
436 | return 0; | ||
437 | break; | ||
438 | case ORANGEFS_TYPE_SYMLINK: | ||
439 | if (!S_ISLNK(inode->i_mode)) | ||
440 | return 0; | ||
441 | if (orangefs_inode && symname && | ||
442 | mask & ORANGEFS_ATTR_SYS_LNK_TARGET) | ||
443 | if (strcmp(orangefs_inode->link_target, symname)) | ||
444 | return 0; | ||
445 | break; | ||
446 | default: | ||
447 | gossip_err("orangefs: compare_attributes_to_inode: got invalid attribute type %x\n", | ||
448 | attrs->objtype); | ||
449 | |||
450 | } | ||
451 | |||
452 | return 1; | ||
453 | } | ||
454 | |||
455 | /* | ||
456 | * Issues a orangefs getattr request and fills in the appropriate inode | ||
457 | * attributes if successful. When check is 0, returns 0 on success and -errno | ||
458 | * otherwise. When check is 1, returns 1 on success where the inode is valid | ||
459 | * and 0 on success where the inode is stale and -errno otherwise. | ||
460 | */ | ||
461 | int orangefs_inode_old_getattr(struct inode *inode, __u32 getattr_mask, | ||
462 | int check) | ||
463 | { | ||
464 | struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); | ||
465 | struct orangefs_kernel_op_s *new_op; | ||
466 | int ret = -EINVAL; | ||
467 | |||
468 | gossip_debug(GOSSIP_UTILS_DEBUG, | ||
469 | "%s: called on inode %pU\n", | ||
470 | __func__, | ||
471 | get_khandle_from_ino(inode)); | ||
472 | |||
473 | new_op = op_alloc(ORANGEFS_VFS_OP_GETATTR); | ||
474 | if (!new_op) | ||
475 | return -ENOMEM; | ||
476 | new_op->upcall.req.getattr.refn = orangefs_inode->refn; | ||
477 | new_op->upcall.req.getattr.mask = getattr_mask; | ||
478 | |||
479 | ret = service_operation(new_op, __func__, | ||
480 | get_interruptible_flag(inode)); | ||
481 | if (ret != 0) | ||
482 | goto out; | ||
483 | |||
484 | if (check) { | ||
485 | ret = compare_attributes_to_inode(inode, | ||
486 | &new_op->downcall.resp.getattr.attributes, | ||
487 | new_op->downcall.resp.getattr.link_target, | ||
488 | getattr_mask); | ||
489 | |||
490 | if (new_op->downcall.resp.getattr.attributes.objtype == | ||
491 | ORANGEFS_TYPE_METAFILE) { | ||
492 | if (orangefs_inode->blksize != | ||
493 | new_op->downcall.resp.getattr.attributes.blksize) | ||
494 | ret = 0; | ||
495 | } else { | ||
496 | if (orangefs_inode->blksize != 1 << inode->i_blkbits) | ||
497 | ret = 0; | ||
498 | } | ||
499 | } else { | ||
500 | if (copy_attributes_to_inode(inode, | ||
501 | &new_op->downcall.resp.getattr.attributes, | ||
502 | new_op->downcall.resp.getattr.link_target)) { | ||
503 | gossip_err("%s: failed to copy attributes\n", __func__); | ||
504 | ret = -ENOENT; | ||
505 | goto out; | ||
506 | } | ||
507 | |||
508 | /* | ||
509 | * Store blksize in orangefs specific part of inode structure; | ||
510 | * we are only going to use this to report to stat to make sure | ||
511 | * it doesn't perturb any inode related code paths. | ||
512 | */ | ||
513 | if (new_op->downcall.resp.getattr.attributes.objtype == | ||
514 | ORANGEFS_TYPE_METAFILE) { | ||
515 | orangefs_inode->blksize = new_op->downcall.resp. | ||
516 | getattr.attributes.blksize; | ||
517 | } else { | ||
518 | /* | ||
519 | * mimic behavior of generic_fillattr() for other file | ||
520 | * types. | ||
521 | */ | ||
522 | orangefs_inode->blksize = (1 << inode->i_blkbits); | ||
523 | |||
524 | } | ||
525 | } | ||
526 | |||
527 | out: | ||
528 | gossip_debug(GOSSIP_UTILS_DEBUG, | ||
529 | "Getattr on handle %pU, " | ||
530 | "fsid %d\n (inode ct = %d) returned %d\n", | ||
531 | &orangefs_inode->refn.khandle, | ||
532 | orangefs_inode->refn.fs_id, | ||
533 | (int)atomic_read(&inode->i_count), | ||
534 | ret); | ||
535 | |||
536 | op_release(new_op); | ||
537 | return ret; | ||
538 | } | ||
539 | |||
540 | static int orangefs_inode_type(enum orangefs_ds_type objtype) | 219 | static int orangefs_inode_type(enum orangefs_ds_type objtype) |
541 | { | 220 | { |
542 | if (objtype == ORANGEFS_TYPE_METAFILE) | 221 | if (objtype == ORANGEFS_TYPE_METAFILE) |
@@ -655,6 +334,52 @@ out: | |||
655 | return ret; | 334 | return ret; |
656 | } | 335 | } |
657 | 336 | ||
337 | int orangefs_inode_check_changed(struct inode *inode) | ||
338 | { | ||
339 | struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); | ||
340 | struct orangefs_kernel_op_s *new_op; | ||
341 | int ret; | ||
342 | |||
343 | gossip_debug(GOSSIP_UTILS_DEBUG, "%s: called on inode %pU\n", __func__, | ||
344 | get_khandle_from_ino(inode)); | ||
345 | |||
346 | new_op = op_alloc(ORANGEFS_VFS_OP_GETATTR); | ||
347 | if (!new_op) | ||
348 | return -ENOMEM; | ||
349 | new_op->upcall.req.getattr.refn = orangefs_inode->refn; | ||
350 | new_op->upcall.req.getattr.mask = ORANGEFS_ATTR_SYS_TYPE | | ||
351 | ORANGEFS_ATTR_SYS_LNK_TARGET; | ||
352 | |||
353 | ret = service_operation(new_op, __func__, | ||
354 | get_interruptible_flag(inode)); | ||
355 | if (ret != 0) | ||
356 | goto out; | ||
357 | |||
358 | ret = orangefs_inode_type(new_op-> | ||
359 | downcall.resp.getattr.attributes.objtype); | ||
360 | /* | ||
361 | * If the inode type or symlink target have changed then this | ||
362 | * inode is stale. | ||
363 | */ | ||
364 | if (ret == -1 || !(inode->i_mode & ret)) { | ||
365 | orangefs_make_bad_inode(inode); | ||
366 | ret = 1; | ||
367 | goto out; | ||
368 | } | ||
369 | if (ret == S_IFLNK && strncmp(orangefs_inode->link_target, | ||
370 | new_op->downcall.resp.getattr.link_target, | ||
371 | ORANGEFS_NAME_MAX)) { | ||
372 | orangefs_make_bad_inode(inode); | ||
373 | ret = 1; | ||
374 | goto out; | ||
375 | } | ||
376 | |||
377 | ret = 0; | ||
378 | out: | ||
379 | op_release(new_op); | ||
380 | return ret; | ||
381 | } | ||
382 | |||
658 | /* | 383 | /* |
659 | * issues a orangefs setattr request to make sure the new attribute values | 384 | * issues a orangefs setattr request to make sure the new attribute values |
660 | * take effect if successful. returns 0 on success; -errno otherwise | 385 | * take effect if successful. returns 0 on success; -errno otherwise |