Module Name: src Committed By: manu Date: Thu Jun 14 05:58:22 UTC 2012
Modified Files: src/lib/libperfuse: ops.c Log Message: Fix memory leak when we discard a voided setattr operation To generate a diff of this commit: cvs rdiff -u -r1.56 -r1.57 src/lib/libperfuse/ops.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/libperfuse/ops.c diff -u src/lib/libperfuse/ops.c:1.56 src/lib/libperfuse/ops.c:1.57 --- src/lib/libperfuse/ops.c:1.56 Wed Jun 13 01:45:56 2012 +++ src/lib/libperfuse/ops.c Thu Jun 14 05:58:22 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: ops.c,v 1.56 2012/06/13 01:45:56 manu Exp $ */ +/* $NetBSD: ops.c,v 1.57 2012/06/14 05:58:22 manu Exp $ */ /*- * Copyright (c) 2010-2011 Emmanuel Dreyfus. All rights reserved. @@ -1696,6 +1696,7 @@ perfuse_node_setattr_ttl(struct puffs_us struct fuse_attr_out *fao; struct vattr *old_va; int error; + int valid; #ifdef PERFUSE_DEBUG struct vattr *old_vap; int resize_debug = 0; @@ -1719,39 +1720,94 @@ perfuse_node_setattr_ttl(struct puffs_us } old_va = puffs_pn_getvap((struct puffs_node *)opc); + valid = 0; /* * Check for permission to change size */ - if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) && - (error = mode_access(opc, pcr, PUFFS_VWRITE)) != 0) - return error; + if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL)) { + if ((error = mode_access(opc, pcr, PUFFS_VWRITE)) != 0) + return error; + valid |= FUSE_FATTR_SIZE; + } /* - * Check for permission to change dates + * Check for permission to change owner and group */ - if (((vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) || - (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)) && - (puffs_access_times(old_va->va_uid, old_va->va_gid, - old_va->va_mode, 0, pcr) != 0)) - return EACCES; + if ((vap->va_uid != (uid_t)PUFFS_VNOVAL) || + (vap->va_gid != (gid_t)PUFFS_VNOVAL)) { + if (puffs_access_chown(old_va->va_uid, old_va->va_gid, + vap->va_uid, vap->va_gid, pcr) != 0) + return EACCES; + + if (vap->va_uid != (uid_t)PUFFS_VNOVAL) + valid |= FUSE_FATTR_UID; + + if (vap->va_gid != (uid_t)PUFFS_VNOVAL) + valid |= FUSE_FATTR_GID; + } /* - * Check for permission to change owner and group + * Check for permission to change permissions */ - if (((vap->va_uid != (uid_t)PUFFS_VNOVAL) || - (vap->va_gid != (gid_t)PUFFS_VNOVAL)) && - (puffs_access_chown(old_va->va_uid, old_va->va_gid, - vap->va_uid, vap->va_gid, pcr)) != 0) - return EACCES; + if (vap->va_mode != (mode_t)PUFFS_VNOVAL) { + if (puffs_access_chmod(old_va->va_uid, old_va->va_gid, + old_va->va_type, vap->va_mode, pcr) != 0) + return EACCES; + valid |= FUSE_FATTR_MODE; + } /* - * Check for permission to change permissions + * Check for permission to change dates */ - if ((vap->va_mode != (mode_t)PUFFS_VNOVAL) && - (puffs_access_chmod(old_va->va_uid, old_va->va_gid, - old_va->va_type, vap->va_mode, pcr)) != 0) - return EACCES; + if ((vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) || + (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)) { + if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) + valid |= FUSE_FATTR_ATIME; + + if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) + valid |= FUSE_FATTR_MTIME; + + /* + * ftruncate() sends only va_size, and metadata cache + * flush adds va_atime and va_mtime. Some FUSE + * filesystems will attempt to detect ftruncate by + * checking for FATTR_SIZE being set without + * FATTR_UID|FATTR_GID|FATTR_ATIME|FATTR_MTIME|FATTR_MODE + * + * Try to adapt and remove FATTR_ATIME|FATTR_MTIME + * if we suspect a ftruncate(). + */ + if ((valid & FUSE_FATTR_SIZE) && + !(valid & (FUSE_FATTR_UID|FUSE_FATTR_GID|FUSE_FATTR_MODE))) + valid &= ~(FUSE_FATTR_ATIME|FUSE_FATTR_MTIME); + + /* + * There is the same mess with fchmod() + */ + if ((valid & FUSE_FATTR_MODE) && + !(valid & (FUSE_FATTR_UID|FUSE_FATTR_GID))) + valid &= ~(FUSE_FATTR_ATIME|FUSE_FATTR_MTIME); + + /* + * And if a change on atime/mtime remains, check permissions. + */ + if ((valid & (FUSE_FATTR_ATIME|FUSE_FATTR_MTIME)) && + (puffs_access_times(old_va->va_uid, old_va->va_gid, + old_va->va_mode, 0, pcr) != 0)) + return EACCES; + } + + /* + * If nothing remain, discard the operation. This happend when + * only ctime is changed. + */ + if (!(valid & (FUSE_FATTR_SIZE|FUSE_FATTR_ATIME|FUSE_FATTR_MTIME| + FUSE_FATTR_MODE|FUSE_FATTR_UID|FUSE_FATTR_GID))) { + error = 0; + goto out; + } + pm = ps->ps_new_msg(pu, opc, FUSE_SETATTR, sizeof(*fsi), pcr); fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in); @@ -1766,7 +1822,7 @@ perfuse_node_setattr_ttl(struct puffs_us fsi->valid |= FUSE_FATTR_FH; } - if (vap->va_size != (u_quad_t)PUFFS_VNOVAL) { + if (valid & FUSE_FATTR_SIZE) { fsi->size = vap->va_size; fsi->valid |= FUSE_FATTR_SIZE; @@ -1787,10 +1843,8 @@ perfuse_node_setattr_ttl(struct puffs_us * dates being reset to Epoch on glusterfs. If one * is missing, use the old value. */ - if ((vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) || - (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL)) { - - if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) { + if (valid & (FUSE_FATTR_ATIME|FUSE_FATTR_MTIME)) { + if (valid & FUSE_FATTR_ATIME) { fsi->atime = vap->va_atime.tv_sec; fsi->atimensec = (uint32_t)vap->va_atime.tv_nsec; } else { @@ -1798,7 +1852,7 @@ perfuse_node_setattr_ttl(struct puffs_us fsi->atimensec = (uint32_t)old_va->va_atime.tv_nsec; } - if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) { + if (valid & FUSE_FATTR_MTIME) { fsi->mtime = vap->va_mtime.tv_sec; fsi->mtimensec = (uint32_t)vap->va_mtime.tv_nsec; } else { @@ -1809,17 +1863,17 @@ perfuse_node_setattr_ttl(struct puffs_us fsi->valid |= (FUSE_FATTR_MTIME|FUSE_FATTR_ATIME); } - if (vap->va_mode != (mode_t)PUFFS_VNOVAL) { + if (valid & FUSE_FATTR_MODE) { fsi->mode = vap->va_mode; fsi->valid |= FUSE_FATTR_MODE; } - if (vap->va_uid != (uid_t)PUFFS_VNOVAL) { + if (valid & FUSE_FATTR_UID) { fsi->uid = vap->va_uid; fsi->valid |= FUSE_FATTR_UID; } - if (vap->va_gid != (gid_t)PUFFS_VNOVAL) { + if (valid & FUSE_FATTR_GID) { fsi->gid = vap->va_gid; fsi->valid |= FUSE_FATTR_GID; } @@ -1829,49 +1883,6 @@ perfuse_node_setattr_ttl(struct puffs_us fsi->valid |= FUSE_FATTR_LOCKOWNER; } - /* - * ftruncate() sends only va_size, and metadata cache - * flush adds va_atime and va_mtime. Some FUSE - * filesystems will attempt to detect ftruncate by - * checking for FATTR_SIZE being set without - * FATTR_UID|FATTR_GID|FATTR_ATIME|FATTR_MTIME|FATTR_MODE - * - * Try to adapt and remove FATTR_ATIME|FATTR_MTIME - * if we suspect a ftruncate(). - */ - if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) && - ((vap->va_mode == (mode_t)PUFFS_VNOVAL) && - (vap->va_uid == (uid_t)PUFFS_VNOVAL) && - (vap->va_gid == (gid_t)PUFFS_VNOVAL))) { - fsi->atime = 0; - fsi->atimensec = 0; - fsi->mtime = 0; - fsi->mtimensec = 0; - fsi->valid &= ~(FUSE_FATTR_ATIME|FUSE_FATTR_MTIME); - } - - /* - * There is the same mess with fchmod() - */ - if ((vap->va_mode != (mode_t)PUFFS_VNOVAL) && - (vap->va_uid == (uid_t)PUFFS_VNOVAL) && - (vap->va_gid == (gid_t)PUFFS_VNOVAL)) { - fsi->atime = 0; - fsi->atimensec = 0; - fsi->mtime = 0; - fsi->mtimensec = 0; - fsi->valid &= ~(FUSE_FATTR_ATIME|FUSE_FATTR_MTIME); - } - - /* - * If nothing remain, discard the operation. - */ - if (!(fsi->valid & (FUSE_FATTR_SIZE|FUSE_FATTR_ATIME|FUSE_FATTR_MTIME| - FUSE_FATTR_MODE|FUSE_FATTR_UID|FUSE_FATTR_GID))) { - ps->ps_destroy_msg(pm); - error = 0; - goto out; - } #ifdef PERFUSE_DEBUG old_vap = puffs_pn_getvap((struct puffs_node *)opc);