···117117118118 /* Now we must perform a getattr to validate the inode contents. */119119120120- ret = orangefs_inode_old_getattr(dentry->d_inode,121121- ORANGEFS_ATTR_SYS_TYPE|ORANGEFS_ATTR_SYS_LNK_TARGET, 1);120120+ ret = orangefs_inode_check_changed(dentry->d_inode);122121 if (ret < 0) {123122 gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d getattr failure.\n",124123 __FILE__, __func__, __LINE__);
+2-2
fs/orangefs/orangefs-kernel.h
···544544 size_t size,545545 int flags);546546547547-int orangefs_inode_old_getattr(struct inode *inode, __u32 mask, int check);548548-549547int orangefs_inode_getattr(struct inode *inode, int new, int size);548548+549549+int orangefs_inode_check_changed(struct inode *inode);550550551551int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr);552552
+46-321
fs/orangefs/orangefs-utils.c
···129129 return perm_mode;130130}131131132132-/* NOTE: symname is ignored unless the inode is a sym link */133133-static int copy_attributes_to_inode(struct inode *inode,134134- struct ORANGEFS_sys_attr_s *attrs,135135- char *symname)136136-{137137- int ret = -1;138138- struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);139139- loff_t inode_size = 0;140140- loff_t rounded_up_size = 0;141141-142142-143143- /*144144- * arbitrarily set the inode block size; FIXME: we need to145145- * resolve the difference between the reported inode blocksize146146- * and the PAGE_CACHE_SIZE, since our block count will always147147- * be wrong.148148- *149149- * For now, we're setting the block count to be the proper150150- * number assuming the block size is 512 bytes, and the size is151151- * rounded up to the nearest 4K. This is apparently required152152- * to get proper size reports from the 'du' shell utility.153153- *154154- * changing the inode->i_blkbits to something other than155155- * PAGE_CACHE_SHIFT breaks mmap/execution as we depend on that.156156- */157157- gossip_debug(GOSSIP_UTILS_DEBUG,158158- "attrs->mask = %x (objtype = %s)\n",159159- attrs->mask,160160- attrs->objtype == ORANGEFS_TYPE_METAFILE ? "file" :161161- attrs->objtype == ORANGEFS_TYPE_DIRECTORY ? "directory" :162162- attrs->objtype == ORANGEFS_TYPE_SYMLINK ? "symlink" :163163- "invalid/unknown");164164-165165- switch (attrs->objtype) {166166- case ORANGEFS_TYPE_METAFILE:167167- inode->i_flags = orangefs_inode_flags(attrs);168168- if (attrs->mask & ORANGEFS_ATTR_SYS_SIZE) {169169- inode_size = (loff_t) attrs->size;170170- rounded_up_size =171171- (inode_size + (4096 - (inode_size % 4096)));172172-173173- spin_lock(&inode->i_lock);174174- inode->i_bytes = inode_size;175175- inode->i_blocks =176176- (unsigned long)(rounded_up_size / 512);177177- spin_unlock(&inode->i_lock);178178-179179- /*180180- * NOTE: make sure all the places we're called181181- * from have the inode->i_sem lock. We're fine182182- * in 99% of the cases since we're mostly183183- * called from a lookup.184184- */185185- inode->i_size = inode_size;186186- }187187- break;188188- case ORANGEFS_TYPE_SYMLINK:189189- if (symname != NULL) {190190- inode->i_size = (loff_t) strlen(symname);191191- break;192192- }193193- /*FALLTHRU*/194194- default:195195- inode->i_size = PAGE_CACHE_SIZE;196196-197197- spin_lock(&inode->i_lock);198198- inode_set_bytes(inode, inode->i_size);199199- spin_unlock(&inode->i_lock);200200- break;201201- }202202-203203- inode->i_uid = make_kuid(&init_user_ns, attrs->owner);204204- inode->i_gid = make_kgid(&init_user_ns, attrs->group);205205- inode->i_atime.tv_sec = (time64_t) attrs->atime;206206- inode->i_mtime.tv_sec = (time64_t) attrs->mtime;207207- inode->i_ctime.tv_sec = (time64_t) attrs->ctime;208208- inode->i_atime.tv_nsec = 0;209209- inode->i_mtime.tv_nsec = 0;210210- inode->i_ctime.tv_nsec = 0;211211-212212- inode->i_mode = orangefs_inode_perms(attrs);213213-214214- if (is_root_handle(inode)) {215215- /* special case: mark the root inode as sticky */216216- inode->i_mode |= S_ISVTX;217217- gossip_debug(GOSSIP_UTILS_DEBUG,218218- "Marking inode %pU as sticky\n",219219- get_khandle_from_ino(inode));220220- }221221-222222- switch (attrs->objtype) {223223- case ORANGEFS_TYPE_METAFILE:224224- inode->i_mode |= S_IFREG;225225- ret = 0;226226- break;227227- case ORANGEFS_TYPE_DIRECTORY:228228- inode->i_mode |= S_IFDIR;229229- /* NOTE: we have no good way to keep nlink consistent230230- * for directories across clients; keep constant at 1.231231- * Why 1? If we go with 2, then find(1) gets confused232232- * and won't work properly withouth the -noleaf option233233- */234234- set_nlink(inode, 1);235235- ret = 0;236236- break;237237- case ORANGEFS_TYPE_SYMLINK:238238- inode->i_mode |= S_IFLNK;239239-240240- /* copy link target to inode private data */241241- if (orangefs_inode && symname) {242242- strncpy(orangefs_inode->link_target,243243- symname,244244- ORANGEFS_NAME_MAX);245245- gossip_debug(GOSSIP_UTILS_DEBUG,246246- "Copied attr link target %s\n",247247- orangefs_inode->link_target);248248- }249249- gossip_debug(GOSSIP_UTILS_DEBUG,250250- "symlink mode %o\n",251251- inode->i_mode);252252- ret = 0;253253- break;254254- default:255255- gossip_err("orangefs: copy_attributes_to_inode: got invalid attribute type %x\n",256256- attrs->objtype);257257- }258258-259259- gossip_debug(GOSSIP_UTILS_DEBUG,260260- "orangefs: copy_attributes_to_inode: setting i_mode to %o, i_size to %lu\n",261261- inode->i_mode,262262- (unsigned long)i_size_read(inode));263263-264264- return ret;265265-}266266-267132/*268133 * NOTE: in kernel land, we never use the sys_attr->link_target for269134 * anything, so don't bother copying it into the sys_attr object here.···214349 }215350216351 return 0;217217-}218218-219219-static int compare_attributes_to_inode(struct inode *inode,220220- struct ORANGEFS_sys_attr_s *attrs,221221- char *symname,222222- int mask)223223-{224224- struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);225225- loff_t inode_size, rounded_up_size;226226-227227- /* Much of what happens below relies on the type being around. */228228- if (!(mask & ORANGEFS_ATTR_SYS_TYPE))229229- return 0;230230-231231- if (attrs->objtype == ORANGEFS_TYPE_METAFILE &&232232- inode->i_flags != orangefs_inode_flags(attrs))233233- return 0;234234-235235- /* Compare file size. */236236-237237- switch (attrs->objtype) {238238- case ORANGEFS_TYPE_METAFILE:239239- if (mask & ORANGEFS_ATTR_SYS_SIZE) {240240- inode_size = attrs->size;241241- rounded_up_size = inode_size +242242- (4096 - (inode_size % 4096));243243- if (inode->i_bytes != inode_size ||244244- inode->i_blocks != rounded_up_size/512)245245- return 0;246246- }247247- break;248248- case ORANGEFS_TYPE_SYMLINK:249249- if (mask & ORANGEFS_ATTR_SYS_SIZE)250250- if (symname && strlen(symname) != inode->i_size)251251- return 0;252252- break;253253- default:254254- if (inode->i_size != PAGE_CACHE_SIZE &&255255- inode_get_bytes(inode) != PAGE_CACHE_SIZE)256256- return 0;257257- }258258-259259- /* Compare general attributes. */260260-261261- if (mask & ORANGEFS_ATTR_SYS_UID &&262262- !uid_eq(inode->i_uid, make_kuid(&init_user_ns, attrs->owner)))263263- return 0;264264- if (mask & ORANGEFS_ATTR_SYS_GID &&265265- !gid_eq(inode->i_gid, make_kgid(&init_user_ns, attrs->group)))266266- return 0;267267- if (mask & ORANGEFS_ATTR_SYS_ATIME &&268268- inode->i_atime.tv_sec != attrs->atime)269269- return 0;270270- if (mask & ORANGEFS_ATTR_SYS_MTIME &&271271- inode->i_atime.tv_sec != attrs->mtime)272272- return 0;273273- if (mask & ORANGEFS_ATTR_SYS_CTIME &&274274- inode->i_atime.tv_sec != attrs->ctime)275275- return 0;276276- if (inode->i_atime.tv_nsec != 0 ||277277- inode->i_mtime.tv_nsec != 0 ||278278- inode->i_ctime.tv_nsec != 0)279279- return 0;280280-281281- if (mask & ORANGEFS_ATTR_SYS_PERM &&282282- (inode->i_mode & ~(S_ISVTX|S_IFREG|S_IFDIR|S_IFLNK)) !=283283- orangefs_inode_perms(attrs))284284- return 0;285285-286286- if (is_root_handle(inode))287287- if (!(inode->i_mode & S_ISVTX))288288- return 0;289289-290290- /* Compare file type. */291291-292292- switch (attrs->objtype) {293293- case ORANGEFS_TYPE_METAFILE:294294- if (!S_ISREG(inode->i_mode))295295- return 0;296296- break;297297- case ORANGEFS_TYPE_DIRECTORY:298298- if (!S_ISDIR(inode->i_mode))299299- return 0;300300- if (inode->i_nlink != 1)301301- return 0;302302- break;303303- case ORANGEFS_TYPE_SYMLINK:304304- if (!S_ISLNK(inode->i_mode))305305- return 0;306306- if (orangefs_inode && symname &&307307- mask & ORANGEFS_ATTR_SYS_LNK_TARGET)308308- if (strcmp(orangefs_inode->link_target, symname))309309- return 0;310310- break;311311- default:312312- gossip_err("orangefs: compare_attributes_to_inode: got invalid attribute type %x\n",313313- attrs->objtype);314314-315315- }316316-317317- return 1;318318-}319319-320320-/*321321- * Issues a orangefs getattr request and fills in the appropriate inode322322- * attributes if successful. When check is 0, returns 0 on success and -errno323323- * otherwise. When check is 1, returns 1 on success where the inode is valid324324- * and 0 on success where the inode is stale and -errno otherwise.325325- */326326-int orangefs_inode_old_getattr(struct inode *inode, __u32 getattr_mask,327327- int check)328328-{329329- struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);330330- struct orangefs_kernel_op_s *new_op;331331- int ret = -EINVAL;332332-333333- gossip_debug(GOSSIP_UTILS_DEBUG,334334- "%s: called on inode %pU\n",335335- __func__,336336- get_khandle_from_ino(inode));337337-338338- new_op = op_alloc(ORANGEFS_VFS_OP_GETATTR);339339- if (!new_op)340340- return -ENOMEM;341341- new_op->upcall.req.getattr.refn = orangefs_inode->refn;342342- new_op->upcall.req.getattr.mask = getattr_mask;343343-344344- ret = service_operation(new_op, __func__,345345- get_interruptible_flag(inode));346346- if (ret != 0)347347- goto out;348348-349349- if (check) {350350- ret = compare_attributes_to_inode(inode,351351- &new_op->downcall.resp.getattr.attributes,352352- new_op->downcall.resp.getattr.link_target,353353- getattr_mask);354354-355355- if (new_op->downcall.resp.getattr.attributes.objtype ==356356- ORANGEFS_TYPE_METAFILE) {357357- if (orangefs_inode->blksize !=358358- new_op->downcall.resp.getattr.attributes.blksize)359359- ret = 0;360360- } else {361361- if (orangefs_inode->blksize != 1 << inode->i_blkbits)362362- ret = 0;363363- }364364- } else {365365- if (copy_attributes_to_inode(inode,366366- &new_op->downcall.resp.getattr.attributes,367367- new_op->downcall.resp.getattr.link_target)) {368368- gossip_err("%s: failed to copy attributes\n", __func__);369369- ret = -ENOENT;370370- goto out;371371- }372372-373373- /*374374- * Store blksize in orangefs specific part of inode structure;375375- * we are only going to use this to report to stat to make sure376376- * it doesn't perturb any inode related code paths.377377- */378378- if (new_op->downcall.resp.getattr.attributes.objtype ==379379- ORANGEFS_TYPE_METAFILE) {380380- orangefs_inode->blksize = new_op->downcall.resp.381381- getattr.attributes.blksize;382382- } else {383383- /*384384- * mimic behavior of generic_fillattr() for other file385385- * types.386386- */387387- orangefs_inode->blksize = (1 << inode->i_blkbits);388388-389389- }390390- }391391-392392-out:393393- gossip_debug(GOSSIP_UTILS_DEBUG,394394- "Getattr on handle %pU, "395395- "fsid %d\n (inode ct = %d) returned %d\n",396396- &orangefs_inode->refn.khandle,397397- orangefs_inode->refn.fs_id,398398- (int)atomic_read(&inode->i_count),399399- ret);400400-401401- op_release(new_op);402402- return ret;403352}404353405354static int orangefs_inode_type(enum orangefs_ds_type objtype)···327648 /* special case: mark the root inode as sticky */328649 inode->i_mode = ret | (is_root_handle(inode) ? S_ISVTX : 0) |329650 orangefs_inode_perms(&new_op->downcall.resp.getattr.attributes);651651+652652+ ret = 0;653653+out:654654+ op_release(new_op);655655+ return ret;656656+}657657+658658+int orangefs_inode_check_changed(struct inode *inode)659659+{660660+ struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);661661+ struct orangefs_kernel_op_s *new_op;662662+ int ret;663663+664664+ gossip_debug(GOSSIP_UTILS_DEBUG, "%s: called on inode %pU\n", __func__,665665+ get_khandle_from_ino(inode));666666+667667+ new_op = op_alloc(ORANGEFS_VFS_OP_GETATTR);668668+ if (!new_op)669669+ return -ENOMEM;670670+ new_op->upcall.req.getattr.refn = orangefs_inode->refn;671671+ new_op->upcall.req.getattr.mask = ORANGEFS_ATTR_SYS_TYPE |672672+ ORANGEFS_ATTR_SYS_LNK_TARGET;673673+674674+ ret = service_operation(new_op, __func__,675675+ get_interruptible_flag(inode));676676+ if (ret != 0)677677+ goto out;678678+679679+ ret = orangefs_inode_type(new_op->680680+ downcall.resp.getattr.attributes.objtype);681681+ /*682682+ * If the inode type or symlink target have changed then this683683+ * inode is stale.684684+ */685685+ if (ret == -1 || !(inode->i_mode & ret)) {686686+ orangefs_make_bad_inode(inode);687687+ ret = 1;688688+ goto out;689689+ }690690+ if (ret == S_IFLNK && strncmp(orangefs_inode->link_target,691691+ new_op->downcall.resp.getattr.link_target,692692+ ORANGEFS_NAME_MAX)) {693693+ orangefs_make_bad_inode(inode);694694+ ret = 1;695695+ goto out;696696+ }330697331698 ret = 0;332699out: