1*5db11c21SMike Marshall /* 2*5db11c21SMike Marshall * (C) 2001 Clemson University and The University of Chicago 3*5db11c21SMike Marshall * 4*5db11c21SMike Marshall * See COPYING in top-level directory. 5*5db11c21SMike Marshall */ 6*5db11c21SMike Marshall 7*5db11c21SMike Marshall #include "protocol.h" 8*5db11c21SMike Marshall #include "pvfs2-kernel.h" 9*5db11c21SMike Marshall #include "pvfs2-bufmap.h" 10*5db11c21SMike Marshall #include <linux/posix_acl_xattr.h> 11*5db11c21SMike Marshall #include <linux/fs_struct.h> 12*5db11c21SMike Marshall 13*5db11c21SMike Marshall struct posix_acl *pvfs2_get_acl(struct inode *inode, int type) 14*5db11c21SMike Marshall { 15*5db11c21SMike Marshall struct posix_acl *acl; 16*5db11c21SMike Marshall int ret; 17*5db11c21SMike Marshall char *key = NULL, *value = NULL; 18*5db11c21SMike Marshall 19*5db11c21SMike Marshall switch (type) { 20*5db11c21SMike Marshall case ACL_TYPE_ACCESS: 21*5db11c21SMike Marshall key = PVFS2_XATTR_NAME_ACL_ACCESS; 22*5db11c21SMike Marshall break; 23*5db11c21SMike Marshall case ACL_TYPE_DEFAULT: 24*5db11c21SMike Marshall key = PVFS2_XATTR_NAME_ACL_DEFAULT; 25*5db11c21SMike Marshall break; 26*5db11c21SMike Marshall default: 27*5db11c21SMike Marshall gossip_err("pvfs2_get_acl: bogus value of type %d\n", type); 28*5db11c21SMike Marshall return ERR_PTR(-EINVAL); 29*5db11c21SMike Marshall } 30*5db11c21SMike Marshall /* 31*5db11c21SMike Marshall * Rather than incurring a network call just to determine the exact 32*5db11c21SMike Marshall * length of the attribute, I just allocate a max length to save on 33*5db11c21SMike Marshall * the network call. Conceivably, we could pass NULL to 34*5db11c21SMike Marshall * pvfs2_inode_getxattr() to probe the length of the value, but 35*5db11c21SMike Marshall * I don't do that for now. 36*5db11c21SMike Marshall */ 37*5db11c21SMike Marshall value = kmalloc(PVFS_MAX_XATTR_VALUELEN, GFP_KERNEL); 38*5db11c21SMike Marshall if (value == NULL) 39*5db11c21SMike Marshall return ERR_PTR(-ENOMEM); 40*5db11c21SMike Marshall 41*5db11c21SMike Marshall gossip_debug(GOSSIP_ACL_DEBUG, 42*5db11c21SMike Marshall "inode %pU, key %s, type %d\n", 43*5db11c21SMike Marshall get_khandle_from_ino(inode), 44*5db11c21SMike Marshall key, 45*5db11c21SMike Marshall type); 46*5db11c21SMike Marshall ret = pvfs2_inode_getxattr(inode, 47*5db11c21SMike Marshall "", 48*5db11c21SMike Marshall key, 49*5db11c21SMike Marshall value, 50*5db11c21SMike Marshall PVFS_MAX_XATTR_VALUELEN); 51*5db11c21SMike Marshall /* if the key exists, convert it to an in-memory rep */ 52*5db11c21SMike Marshall if (ret > 0) { 53*5db11c21SMike Marshall acl = posix_acl_from_xattr(&init_user_ns, value, ret); 54*5db11c21SMike Marshall } else if (ret == -ENODATA || ret == -ENOSYS) { 55*5db11c21SMike Marshall acl = NULL; 56*5db11c21SMike Marshall } else { 57*5db11c21SMike Marshall gossip_err("inode %pU retrieving acl's failed with error %d\n", 58*5db11c21SMike Marshall get_khandle_from_ino(inode), 59*5db11c21SMike Marshall ret); 60*5db11c21SMike Marshall acl = ERR_PTR(ret); 61*5db11c21SMike Marshall } 62*5db11c21SMike Marshall /* kfree(NULL) is safe, so don't worry if value ever got used */ 63*5db11c21SMike Marshall kfree(value); 64*5db11c21SMike Marshall return acl; 65*5db11c21SMike Marshall } 66*5db11c21SMike Marshall 67*5db11c21SMike Marshall int pvfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type) 68*5db11c21SMike Marshall { 69*5db11c21SMike Marshall struct pvfs2_inode_s *pvfs2_inode = PVFS2_I(inode); 70*5db11c21SMike Marshall int error = 0; 71*5db11c21SMike Marshall void *value = NULL; 72*5db11c21SMike Marshall size_t size = 0; 73*5db11c21SMike Marshall const char *name = NULL; 74*5db11c21SMike Marshall 75*5db11c21SMike Marshall switch (type) { 76*5db11c21SMike Marshall case ACL_TYPE_ACCESS: 77*5db11c21SMike Marshall name = PVFS2_XATTR_NAME_ACL_ACCESS; 78*5db11c21SMike Marshall if (acl) { 79*5db11c21SMike Marshall umode_t mode = inode->i_mode; 80*5db11c21SMike Marshall /* 81*5db11c21SMike Marshall * can we represent this with the traditional file 82*5db11c21SMike Marshall * mode permission bits? 83*5db11c21SMike Marshall */ 84*5db11c21SMike Marshall error = posix_acl_equiv_mode(acl, &mode); 85*5db11c21SMike Marshall if (error < 0) { 86*5db11c21SMike Marshall gossip_err("%s: posix_acl_equiv_mode err: %d\n", 87*5db11c21SMike Marshall __func__, 88*5db11c21SMike Marshall error); 89*5db11c21SMike Marshall return error; 90*5db11c21SMike Marshall } 91*5db11c21SMike Marshall 92*5db11c21SMike Marshall if (inode->i_mode != mode) 93*5db11c21SMike Marshall SetModeFlag(pvfs2_inode); 94*5db11c21SMike Marshall inode->i_mode = mode; 95*5db11c21SMike Marshall mark_inode_dirty_sync(inode); 96*5db11c21SMike Marshall if (error == 0) 97*5db11c21SMike Marshall acl = NULL; 98*5db11c21SMike Marshall } 99*5db11c21SMike Marshall break; 100*5db11c21SMike Marshall case ACL_TYPE_DEFAULT: 101*5db11c21SMike Marshall name = PVFS2_XATTR_NAME_ACL_DEFAULT; 102*5db11c21SMike Marshall break; 103*5db11c21SMike Marshall default: 104*5db11c21SMike Marshall gossip_err("%s: invalid type %d!\n", __func__, type); 105*5db11c21SMike Marshall return -EINVAL; 106*5db11c21SMike Marshall } 107*5db11c21SMike Marshall 108*5db11c21SMike Marshall gossip_debug(GOSSIP_ACL_DEBUG, 109*5db11c21SMike Marshall "%s: inode %pU, key %s type %d\n", 110*5db11c21SMike Marshall __func__, get_khandle_from_ino(inode), 111*5db11c21SMike Marshall name, 112*5db11c21SMike Marshall type); 113*5db11c21SMike Marshall 114*5db11c21SMike Marshall if (acl) { 115*5db11c21SMike Marshall size = posix_acl_xattr_size(acl->a_count); 116*5db11c21SMike Marshall value = kmalloc(size, GFP_KERNEL); 117*5db11c21SMike Marshall if (!value) 118*5db11c21SMike Marshall return -ENOMEM; 119*5db11c21SMike Marshall 120*5db11c21SMike Marshall error = posix_acl_to_xattr(&init_user_ns, acl, value, size); 121*5db11c21SMike Marshall if (error < 0) 122*5db11c21SMike Marshall goto out; 123*5db11c21SMike Marshall } 124*5db11c21SMike Marshall 125*5db11c21SMike Marshall gossip_debug(GOSSIP_ACL_DEBUG, 126*5db11c21SMike Marshall "%s: name %s, value %p, size %zd, acl %p\n", 127*5db11c21SMike Marshall __func__, name, value, size, acl); 128*5db11c21SMike Marshall /* 129*5db11c21SMike Marshall * Go ahead and set the extended attribute now. NOTE: Suppose acl 130*5db11c21SMike Marshall * was NULL, then value will be NULL and size will be 0 and that 131*5db11c21SMike Marshall * will xlate to a removexattr. However, we don't want removexattr 132*5db11c21SMike Marshall * complain if attributes does not exist. 133*5db11c21SMike Marshall */ 134*5db11c21SMike Marshall error = pvfs2_inode_setxattr(inode, "", name, value, size, 0); 135*5db11c21SMike Marshall 136*5db11c21SMike Marshall out: 137*5db11c21SMike Marshall kfree(value); 138*5db11c21SMike Marshall if (!error) 139*5db11c21SMike Marshall set_cached_acl(inode, type, acl); 140*5db11c21SMike Marshall return error; 141*5db11c21SMike Marshall } 142*5db11c21SMike Marshall 143*5db11c21SMike Marshall int pvfs2_init_acl(struct inode *inode, struct inode *dir) 144*5db11c21SMike Marshall { 145*5db11c21SMike Marshall struct pvfs2_inode_s *pvfs2_inode = PVFS2_I(inode); 146*5db11c21SMike Marshall struct posix_acl *default_acl, *acl; 147*5db11c21SMike Marshall umode_t mode = inode->i_mode; 148*5db11c21SMike Marshall int error = 0; 149*5db11c21SMike Marshall 150*5db11c21SMike Marshall ClearModeFlag(pvfs2_inode); 151*5db11c21SMike Marshall 152*5db11c21SMike Marshall error = posix_acl_create(dir, &mode, &default_acl, &acl); 153*5db11c21SMike Marshall if (error) 154*5db11c21SMike Marshall return error; 155*5db11c21SMike Marshall 156*5db11c21SMike Marshall if (default_acl) { 157*5db11c21SMike Marshall error = pvfs2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); 158*5db11c21SMike Marshall posix_acl_release(default_acl); 159*5db11c21SMike Marshall } 160*5db11c21SMike Marshall 161*5db11c21SMike Marshall if (acl) { 162*5db11c21SMike Marshall if (!error) 163*5db11c21SMike Marshall error = pvfs2_set_acl(inode, acl, ACL_TYPE_ACCESS); 164*5db11c21SMike Marshall posix_acl_release(acl); 165*5db11c21SMike Marshall } 166*5db11c21SMike Marshall 167*5db11c21SMike Marshall /* If mode of the inode was changed, then do a forcible ->setattr */ 168*5db11c21SMike Marshall if (mode != inode->i_mode) { 169*5db11c21SMike Marshall SetModeFlag(pvfs2_inode); 170*5db11c21SMike Marshall inode->i_mode = mode; 171*5db11c21SMike Marshall pvfs2_flush_inode(inode); 172*5db11c21SMike Marshall } 173*5db11c21SMike Marshall 174*5db11c21SMike Marshall return error; 175*5db11c21SMike Marshall } 176