int orangefs_init_acl(struct inode *inode, struct inode *dir) { struct posix_acl *default_acl, *acl; umode_t mode = inode->i_mode; struct iattr iattr; int error = 0; error = posix_acl_create(dir, &mode, &default_acl, &acl); if (error) return error; if (default_acl) { error = __orangefs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); posix_acl_release(default_acl); } if (acl) { if (!error) error = __orangefs_set_acl(inode, acl, ACL_TYPE_ACCESS); posix_acl_release(acl); } /* If mode of the inode was changed, then do a forcible ->setattr */ if (mode != inode->i_mode) { memset(&iattr, 0, sizeof iattr); inode->i_mode = mode; iattr.ia_mode = mode; iattr.ia_valid |= ATTR_MODE; orangefs_inode_setattr(inode, &iattr); } return error; }
/* * No need for i_mutex because the inode is not yet exposed to the VFS. */ int xfs_inherit_acl(struct inode *inode, struct posix_acl *acl) { umode_t mode = inode->i_mode; int error = 0, inherit = 0; if (S_ISDIR(inode->i_mode)) { error = xfs_set_acl(inode, ACL_TYPE_DEFAULT, acl); if (error) goto out; } error = posix_acl_create(&acl, GFP_KERNEL, &mode); if (error < 0) return error; /* * If posix_acl_create returns a positive value we need to * inherit a permission that can't be represented using the Unix * mode bits and we actually need to set an ACL. */ if (error > 0) inherit = 1; error = xfs_set_mode(inode, mode); if (error) goto out; if (inherit) error = xfs_set_acl(inode, ACL_TYPE_ACCESS, acl); out: posix_acl_release(acl); return error; }
int orangefs_init_acl(struct inode *inode, struct inode *dir) { struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); struct posix_acl *default_acl, *acl; umode_t mode = inode->i_mode; int error = 0; ClearModeFlag(orangefs_inode); error = posix_acl_create(dir, &mode, &default_acl, &acl); if (error) return error; if (default_acl) { error = orangefs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); posix_acl_release(default_acl); } if (acl) { if (!error) error = orangefs_set_acl(inode, acl, ACL_TYPE_ACCESS); posix_acl_release(acl); } /* If mode of the inode was changed, then do a forcible ->setattr */ if (mode != inode->i_mode) { SetModeFlag(orangefs_inode); inode->i_mode = mode; orangefs_flush_inode(inode); } return error; }
int f2fs_init_acl(struct inode *inode, struct inode *dir) { struct posix_acl *acl = NULL; struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); int error = 0; if (!S_ISLNK(inode->i_mode)) { if (test_opt(sbi, POSIX_ACL)) { acl = f2fs_get_acl(dir, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) return PTR_ERR(acl); } if (!acl) inode->i_mode &= ~current_umask(); } if (test_opt(sbi, POSIX_ACL) && acl) { if (S_ISDIR(inode->i_mode)) { error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl); if (error) goto cleanup; } error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); if (error < 0) return error; if (error > 0) error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl); } cleanup: posix_acl_release(acl); return error; }
int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir) { struct posix_acl *acl = NULL; int rc = 0; if (S_ISLNK(inode->i_mode)) return 0; acl = jfs_get_acl(dir, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) return PTR_ERR(acl); if (acl) { if (S_ISDIR(inode->i_mode)) { rc = jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, acl); if (rc) goto cleanup; } rc = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); if (rc < 0) goto cleanup; /* posix_acl_release(NULL) is no-op */ if (rc > 0) rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl); cleanup: posix_acl_release(acl); } else inode->i_mode &= ~current_umask(); JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) | inode->i_mode; return rc; }
int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, umode_t *i_mode) { struct posix_acl *acl; int rc; cache_no_acl(inode); if (S_ISLNK(*i_mode)) return 0; /* Symlink always has no-ACL */ acl = jffs2_get_acl(dir_i, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) return PTR_ERR(acl); if (!acl) { *i_mode &= ~current_umask(); } else { if (S_ISDIR(*i_mode)) set_cached_acl(inode, ACL_TYPE_DEFAULT, acl); rc = posix_acl_create(&acl, GFP_KERNEL, i_mode); if (rc < 0) return rc; if (rc > 0) set_cached_acl(inode, ACL_TYPE_ACCESS, acl); posix_acl_release(acl); } return 0; }
/* * btrfs_init_acl is already generally called under fs_mutex, so the locking * stuff has been fixed to work with that. If the locking stuff changes, we * need to re-evaluate the acl locking stuff. */ int btrfs_init_acl(struct btrfs_trans_handle *trans, struct inode *inode, struct inode *dir) { struct posix_acl *default_acl, *acl; int ret = 0; /* this happens with subvols */ if (!dir) return 0; ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); if (ret) return ret; if (default_acl) { ret = __btrfs_set_acl(trans, inode, default_acl, ACL_TYPE_DEFAULT); posix_acl_release(default_acl); } if (acl) { if (!ret) ret = __btrfs_set_acl(trans, inode, acl, ACL_TYPE_ACCESS); posix_acl_release(acl); } if (!default_acl && !acl) cache_no_acl(inode); return ret; }
int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir) { struct posix_acl *default_acl, *acl; int rc = 0; rc = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); if (rc) return rc; if (default_acl) { rc = __jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, default_acl); posix_acl_release(default_acl); } if (acl) { if (!rc) rc = __jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl); posix_acl_release(acl); } JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) | inode->i_mode; return rc; }
/* * Initialize the ACLs of a new inode. Called from ext2_new_inode. * * dir->i_mutex: down * inode->i_mutex: up (access to inode is still exclusive) */ int ext2_init_acl(struct inode *inode, struct inode *dir) { struct posix_acl *acl = NULL; int error = 0; if (!S_ISLNK(inode->i_mode)) { if (test_opt(dir->i_sb, POSIX_ACL)) { acl = ext2_get_acl(dir, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) return PTR_ERR(acl); } if (!acl) inode->i_mode &= ~current_umask(); } if (test_opt(inode->i_sb, POSIX_ACL) && acl) { if (S_ISDIR(inode->i_mode)) { error = ext2_set_acl(inode, ACL_TYPE_DEFAULT, acl); if (error) goto cleanup; } error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); if (error < 0) return error; if (error > 0) { /* This is an extended ACL */ error = ext2_set_acl(inode, ACL_TYPE_ACCESS, acl); } } cleanup: posix_acl_release(acl); return error; }
int v9fs_acl_mode(struct inode *dir, mode_t *modep, struct posix_acl **dpacl, struct posix_acl **pacl) { int retval = 0; mode_t mode = *modep; struct posix_acl *acl = NULL; if (!S_ISLNK(mode)) { acl = v9fs_get_cached_acl(dir, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) return PTR_ERR(acl); if (!acl) mode &= ~current_umask(); } if (acl) { if (S_ISDIR(mode)) *dpacl = posix_acl_dup(acl); retval = posix_acl_create(&acl, GFP_NOFS, &mode); if (retval < 0) return retval; if (retval > 0) *pacl = acl; else posix_acl_release(acl); } *modep = mode; return 0; }
int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir) { int err = 0; struct posix_acl *default_acl, *acl; hfs_dbg(ACL_MOD, "[%s]: ino %lu, dir->ino %lu\n", __func__, inode->i_ino, dir->i_ino); if (S_ISLNK(inode->i_mode)) return 0; err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); if (err) return err; if (default_acl) { err = hfsplus_set_posix_acl(inode, default_acl, ACL_TYPE_DEFAULT); posix_acl_release(default_acl); } if (acl) { if (!err) err = hfsplus_set_posix_acl(inode, acl, ACL_TYPE_ACCESS); posix_acl_release(acl); } return err; }
/* * Initialize the ACLs of a new inode. If parent directory has default ACL, * then clone to new inode. Called from ocfs2_mknod. */ int ocfs2_init_acl(handle_t *handle, struct inode *inode, struct inode *dir, struct buffer_head *di_bh, struct buffer_head *dir_bh, struct ocfs2_alloc_context *meta_ac, struct ocfs2_alloc_context *data_ac) { struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct posix_acl *acl = NULL; int ret = 0, ret2; umode_t mode; if (!S_ISLNK(inode->i_mode)) { if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT, dir_bh); if (IS_ERR(acl)) return PTR_ERR(acl); } if (!acl) { mode = inode->i_mode & ~current_umask(); ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode); if (ret) { mlog_errno(ret); goto cleanup; } } } if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) { if (S_ISDIR(inode->i_mode)) { ret = ocfs2_set_acl(handle, inode, di_bh, ACL_TYPE_DEFAULT, acl, meta_ac, data_ac); if (ret) goto cleanup; } mode = inode->i_mode; ret = posix_acl_create(&acl, GFP_NOFS, &mode); if (ret < 0) return ret; ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode); if (ret2) { mlog_errno(ret2); ret = ret2; goto cleanup; } if (ret > 0) { ret = ocfs2_set_acl(handle, inode, di_bh, ACL_TYPE_ACCESS, acl, meta_ac, data_ac); } } cleanup: posix_acl_release(acl); return ret; }
/* dir->i_mutex: locked, * inode is new and not released into the wild yet */ int reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th, struct inode *dir, struct dentry *dentry, struct inode *inode) { struct posix_acl *acl; int err = 0; /* ACLs only get applied to files and directories */ if (S_ISLNK(inode->i_mode)) return 0; /* ACLs can only be used on "new" objects, so if it's an old object * there is nothing to inherit from */ if (get_inode_sd_version(dir) == STAT_DATA_V1) goto apply_umask; /* Don't apply ACLs to objects in the .reiserfs_priv tree.. This * would be useless since permissions are ignored, and a pain because * it introduces locking cycles */ if (IS_PRIVATE(dir)) { inode->i_flags |= S_PRIVATE; goto apply_umask; } acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) return PTR_ERR(acl); if (acl) { /* Copy the default ACL to the default ACL of a new directory */ if (S_ISDIR(inode->i_mode)) { err = reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT, acl); if (err) goto cleanup; } /* Now we reconcile the new ACL and the mode, potentially modifying both */ err = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); if (err < 0) return err; /* If we need an ACL.. */ if (err > 0) err = reiserfs_set_acl(th, inode, ACL_TYPE_ACCESS, acl); cleanup: posix_acl_release(acl); } else { apply_umask: /* no ACL, apply umask */ inode->i_mode &= ~current_umask(); } return err; }
/* * dir->i_mutex: locked, * inode is new and not released into the wild yet */ int reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th, struct inode *dir, struct dentry *dentry, struct inode *inode) { struct posix_acl *default_acl, *acl; int err = 0; /* ACLs only get applied to files and directories */ if (S_ISLNK(inode->i_mode)) return 0; /* * ACLs can only be used on "new" objects, so if it's an old object * there is nothing to inherit from */ if (get_inode_sd_version(dir) == STAT_DATA_V1) goto apply_umask; /* * Don't apply ACLs to objects in the .reiserfs_priv tree.. This * would be useless since permissions are ignored, and a pain because * it introduces locking cycles */ if (IS_PRIVATE(dir)) { inode->i_flags |= S_PRIVATE; goto apply_umask; } err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); if (err) return err; if (default_acl) { err = __reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT, default_acl); posix_acl_release(default_acl); } if (acl) { if (!err) err = __reiserfs_set_acl(th, inode, ACL_TYPE_ACCESS, acl); posix_acl_release(acl); } return err; apply_umask: /* no ACL, apply umask */ inode->i_mode &= ~current_umask(); return err; }
int zpl_init_acl(struct inode *ip, struct inode *dir) { struct posix_acl *acl = NULL; int error = 0; if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL) return (0); if (!S_ISLNK(ip->i_mode)) { if (ITOZSB(ip)->z_acl_type == ZFS_ACLTYPE_POSIXACL) { acl = zpl_get_acl(dir, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) return (PTR_ERR(acl)); } if (!acl) { ip->i_mode &= ~current_umask(); ip->i_ctime = current_fs_time(ITOZSB(ip)->z_sb); mark_inode_dirty(ip); return (0); } } if ((ITOZSB(ip)->z_acl_type == ZFS_ACLTYPE_POSIXACL) && acl) { umode_t mode; if (S_ISDIR(ip->i_mode)) { error = zpl_set_acl(ip, ACL_TYPE_DEFAULT, acl); if (error) goto out; } mode = ip->i_mode; error = posix_acl_create(&acl,GFP_KERNEL, &mode); if (error >= 0) { ip->i_mode = mode; mark_inode_dirty(ip); if (error > 0) error = zpl_set_acl(ip, ACL_TYPE_ACCESS, acl); } } out: zpl_posix_acl_release(acl); return (error); }
/* * btrfs_init_acl is already generally called under fs_mutex, so the locking * stuff has been fixed to work with that. If the locking stuff changes, we * need to re-evaluate the acl locking stuff. */ int btrfs_init_acl(struct btrfs_trans_handle *trans, struct inode *inode, struct inode *dir) { struct posix_acl *acl = NULL; int ret = 0; /* this happens with subvols */ if (!dir) return 0; if (!S_ISLNK(inode->i_mode)) { if (IS_POSIXACL(dir)) { acl = btrfs_get_acl(dir, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) return PTR_ERR(acl); } if (!acl) inode->i_mode &= ~current_umask(); } if (IS_POSIXACL(dir) && acl) { if (S_ISDIR(inode->i_mode)) { ret = btrfs_set_acl(trans, inode, acl, ACL_TYPE_DEFAULT); if (ret) goto failed; } ret = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); if (ret < 0) return ret; if (ret > 0) { /* we need an acl */ ret = btrfs_set_acl(trans, inode, acl, ACL_TYPE_ACCESS); } else if (ret < 0) { cache_no_acl(inode); } } else { cache_no_acl(inode); } failed: posix_acl_release(acl); return ret; }
int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct posix_acl *acl; umode_t mode = inode->i_mode; int error = 0; if (!sdp->sd_args.ar_posix_acl) return 0; if (S_ISLNK(inode->i_mode)) return 0; acl = gfs2_get_acl(&dip->i_inode, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) return PTR_ERR(acl); if (!acl) { mode &= ~current_umask(); if (mode != inode->i_mode) error = gfs2_set_mode(inode, mode); return error; } if (S_ISDIR(inode->i_mode)) { error = gfs2_acl_set(inode, ACL_TYPE_DEFAULT, acl); if (error) goto out; } error = posix_acl_create(&acl, GFP_NOFS, &mode); if (error < 0) return error; if (error == 0) goto munge; error = gfs2_acl_set(inode, ACL_TYPE_ACCESS, acl); if (error) goto out; munge: error = gfs2_set_mode(inode, mode); out: posix_acl_release(acl); return error; }
int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, umode_t *i_mode) { struct posix_acl *default_acl, *acl; int rc; cache_no_acl(inode); rc = posix_acl_create(dir_i, i_mode, &default_acl, &acl); if (rc) return rc; if (default_acl) { set_cached_acl(inode, ACL_TYPE_DEFAULT, default_acl); posix_acl_release(default_acl); } if (acl) { set_cached_acl(inode, ACL_TYPE_ACCESS, acl); posix_acl_release(acl); } return 0; }
/* * Initialize the ACLs of a new inode. Called from ext2_new_inode. * * dir->i_mutex: down * inode->i_mutex: up (access to inode is still exclusive) */ int ext2_init_acl(struct inode *inode, struct inode *dir) { struct posix_acl *default_acl, *acl; int error; error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); if (error) return error; if (default_acl) { error = ext2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); posix_acl_release(default_acl); } if (acl) { if (!error) error = ext2_set_acl(inode, acl, ACL_TYPE_ACCESS); posix_acl_release(acl); } return error; }
int ceph_init_acl(struct dentry *dentry, struct inode *inode, struct inode *dir) { struct posix_acl *default_acl, *acl; umode_t new_mode = inode->i_mode; int error; error = posix_acl_create(dir, &new_mode, &default_acl, &acl); if (error) return error; if (!default_acl && !acl) { cache_no_acl(inode); if (new_mode != inode->i_mode) { struct iattr newattrs = { .ia_mode = new_mode, .ia_valid = ATTR_MODE, }; error = ceph_setattr(dentry, &newattrs); } return error; }
/* * Initialize the ACLs of a new inode. Called from ext4_new_inode. * * dir->i_mutex: down * inode->i_mutex: up (access to inode is still exclusive) */ int ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) { struct posix_acl *default_acl, *acl; int error; error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); if (error) return error; if (default_acl) { error = __ext4_set_acl(handle, inode, ACL_TYPE_DEFAULT, default_acl); posix_acl_release(default_acl); } if (acl) { if (!error) error = __ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, acl); posix_acl_release(acl); } return error; }
int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage) { struct posix_acl *default_acl, *acl; int error = 0; error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); if (error) return error; if (default_acl) { error = __f2fs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl, ipage); posix_acl_release(default_acl); } if (acl) { if (error) error = __f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, ipage); posix_acl_release(acl); } return error; }
int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage) { struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); struct posix_acl *acl = NULL; int error = 0; if (!S_ISLNK(inode->i_mode)) { if (test_opt(sbi, POSIX_ACL)) { acl = f2fs_get_acl(dir, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) return PTR_ERR(acl); } #ifdef CONFIG_F2FS_ANDROID_EMULATION_SUPPORT if (!acl && !(test_opt(sbi, ANDROID_EMU) && F2FS_I(inode)->i_advise & FADVISE_ANDROID_EMU)) #else if (!acl) inode->i_mode &= ~current_umask(); } if (!test_opt(sbi, POSIX_ACL) || !acl) goto cleanup; if (S_ISDIR(inode->i_mode)) { error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl, ipage); if (error) goto cleanup; } error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); if (error < 0) return error; if (error > 0) error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, ipage); cleanup: posix_acl_release(acl); return error; }
/** * generic_acl_init - Take care of acl inheritance at @inode create time * * Files created inside a directory with a default ACL inherit the * directory's default ACL. */ int generic_acl_init(struct inode *inode, struct inode *dir) { struct posix_acl *acl = NULL; int error; if (!S_ISLNK(inode->i_mode)) acl = get_cached_acl(dir, ACL_TYPE_DEFAULT); if (acl) { if (S_ISDIR(inode->i_mode)) set_cached_acl(inode, ACL_TYPE_DEFAULT, acl); error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); if (error < 0) return error; if (error > 0) set_cached_acl(inode, ACL_TYPE_ACCESS, acl); } else { inode->i_mode &= ~current_umask(); } error = 0; posix_acl_release(acl); return error; }
static int nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) { struct nfs3_linkargs arg = { .fromfh = NFS_FH(inode), .tofh = NFS_FH(dir), .toname = name->name, .tolen = name->len }; struct nfs3_linkres res; struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_LINK], .rpc_argp = &arg, .rpc_resp = &res, }; int status = -ENOMEM; dprintk("NFS call link %s\n", name->name); res.fattr = nfs_alloc_fattr(); res.dir_attr = nfs_alloc_fattr(); if (res.fattr == NULL || res.dir_attr == NULL) goto out; zql_control_test(NFS_SERVER(inode)); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); nfs_post_op_update_inode(dir, res.dir_attr); nfs_post_op_update_inode(inode, res.fattr); out: nfs_free_fattr(res.dir_attr); nfs_free_fattr(res.fattr); dprintk("NFS reply link: %d\n", status); return status; } static int nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, unsigned int len, struct iattr *sattr) { struct nfs3_createdata *data; int status = -ENOMEM; if (len > NFS3_MAXPATHLEN) return -ENAMETOOLONG; dprintk("NFS call symlink %pd\n", dentry); data = nfs3_alloc_createdata(); if (data == NULL) goto out; data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK]; data->arg.symlink.fromfh = NFS_FH(dir); data->arg.symlink.fromname = dentry->d_name.name; data->arg.symlink.fromlen = dentry->d_name.len; data->arg.symlink.pages = &page; data->arg.symlink.pathlen = len; data->arg.symlink.sattr = sattr; zql_control_test(NFS_SERVER(dir)); status = nfs3_do_create(dir, dentry, data); nfs3_free_createdata(data); out: dprintk("NFS reply symlink: %d\n", status); return status; } static int nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) { struct posix_acl *default_acl, *acl; struct nfs3_createdata *data; int status = -ENOMEM; dprintk("NFS call mkdir %pd\n", dentry); data = nfs3_alloc_createdata(); if (data == NULL) goto out; status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl); if (status) goto out; data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR]; data->arg.mkdir.fh = NFS_FH(dir); data->arg.mkdir.name = dentry->d_name.name; data->arg.mkdir.len = dentry->d_name.len; data->arg.mkdir.sattr = sattr; zql_control_test(NFS_SERVER(dir)); status = nfs3_do_create(dir, dentry, data); if (status != 0) goto out_release_acls; status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl); out_release_acls: posix_acl_release(acl); posix_acl_release(default_acl); out: nfs3_free_createdata(data); dprintk("NFS reply mkdir: %d\n", status); return status; } static int nfs3_proc_rmdir(struct inode *dir, struct qstr *name) { struct nfs_fattr *dir_attr; struct nfs3_diropargs arg = { .fh = NFS_FH(dir), .name = name->name, .len = name->len }; struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_RMDIR], .rpc_argp = &arg, }; int status = -ENOMEM; dprintk("NFS call rmdir %s\n", name->name); dir_attr = nfs_alloc_fattr(); if (dir_attr == NULL) goto out; msg.rpc_resp = dir_attr; zql_control_test(NFS_SERVER(dir)); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); nfs_post_op_update_inode(dir, dir_attr); nfs_free_fattr(dir_attr); out: dprintk("NFS reply rmdir: %d\n", status); return status; } /* * The READDIR implementation is somewhat hackish - we pass the user buffer * to the encode function, which installs it in the receive iovec. * The decode function itself doesn't perform any decoding, it just makes * sure the reply is syntactically correct. * * Also note that this implementation handles both plain readdir and * readdirplus. */ static int nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, u64 cookie, struct page **pages, unsigned int count, int plus) { struct inode *dir = dentry->d_inode; __be32 *verf = NFS_I(dir)->cookieverf; struct nfs3_readdirargs arg = { .fh = NFS_FH(dir), .cookie = cookie, .verf = {verf[0], verf[1]}, .plus = plus, .count = count, .pages = pages }; struct nfs3_readdirres res = { .verf = verf, .plus = plus }; struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_READDIR], .rpc_argp = &arg, .rpc_resp = &res, .rpc_cred = cred }; int status = -ENOMEM; if (plus) msg.rpc_proc = &nfs3_procedures[NFS3PROC_READDIRPLUS]; dprintk("NFS call readdir%s %d\n", plus? "plus" : "", (unsigned int) cookie); res.dir_attr = nfs_alloc_fattr(); if (res.dir_attr == NULL) goto out; zql_control_test(NFS_SERVER(dir)); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); nfs_invalidate_atime(dir); nfs_refresh_inode(dir, res.dir_attr); nfs_free_fattr(res.dir_attr); out: dprintk("NFS reply readdir%s: %d\n", plus? "plus" : "", status); return status; } static int nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, dev_t rdev) { struct posix_acl *default_acl, *acl; struct nfs3_createdata *data; int status = -ENOMEM; dprintk("NFS call mknod %pd %u:%u\n", dentry, MAJOR(rdev), MINOR(rdev)); data = nfs3_alloc_createdata(); if (data == NULL) goto out; status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl); if (status) goto out; data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD]; data->arg.mknod.fh = NFS_FH(dir); data->arg.mknod.name = dentry->d_name.name; data->arg.mknod.len = dentry->d_name.len; data->arg.mknod.sattr = sattr; data->arg.mknod.rdev = rdev; switch (sattr->ia_mode & S_IFMT) { case S_IFBLK: data->arg.mknod.type = NF3BLK; break; case S_IFCHR: data->arg.mknod.type = NF3CHR; break; case S_IFIFO: data->arg.mknod.type = NF3FIFO; break; case S_IFSOCK: data->arg.mknod.type = NF3SOCK; break; default: status = -EINVAL; goto out; } zql_control_test(NFS_SERVER(dir)); status = nfs3_do_create(dir, dentry, data); if (status != 0) goto out_release_acls; status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl); out_release_acls: posix_acl_release(acl); posix_acl_release(default_acl); out: nfs3_free_createdata(data); dprintk("NFS reply mknod: %d\n", status); return status; } static int nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *stat) { struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_FSSTAT], .rpc_argp = fhandle, .rpc_resp = stat, }; int status; dprintk("NFS call fsstat\n"); nfs_fattr_init(stat->fattr); zql_control_test(server); status = rpc_call_sync(server->client, &msg, 0); dprintk("NFS reply fsstat: %d\n", status); return status; } static int do_proc_fsinfo(struct rpc_clnt *client, struct nfs_fh *fhandle, struct nfs_fsinfo *info) { struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_FSINFO], .rpc_argp = fhandle, .rpc_resp = info, }; int status; dprintk("NFS call fsinfo\n"); nfs_fattr_init(info->fattr); status = rpc_call_sync(client, &msg, 0); dprintk("NFS reply fsinfo: %d\n", status); return status; } /* * Bare-bones access to fsinfo: this is for nfs_get_root/nfs_get_sb via * nfs_create_server */ static int nfs3_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *info) { int status; zql_control_test(server); status = do_proc_fsinfo(server->client, fhandle, info); if (status && server->nfs_client->cl_rpcclient != server->client) status = do_proc_fsinfo(server->nfs_client->cl_rpcclient, fhandle, info); return status; }
/* * Create a regular file. */ static int nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, int flags) { struct posix_acl *default_acl, *acl; struct nfs3_createdata *data; int status = -ENOMEM; dprintk("NFS call create %pd\n", dentry); data = nfs3_alloc_createdata(); if (data == NULL) goto out; data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_CREATE]; data->arg.create.fh = NFS_FH(dir); data->arg.create.name = dentry->d_name.name; data->arg.create.len = dentry->d_name.len; data->arg.create.sattr = sattr; data->arg.create.createmode = NFS3_CREATE_UNCHECKED; if (flags & O_EXCL) { data->arg.create.createmode = NFS3_CREATE_EXCLUSIVE; data->arg.create.verifier[0] = cpu_to_be32(jiffies); data->arg.create.verifier[1] = cpu_to_be32(current->pid); } status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl); if (status) goto out; zql_control_test(NFS_SERVER(dir)); for (;;) { status = nfs3_do_create(dir, dentry, data); if (status != -ENOTSUPP) break; /* If the server doesn't support the exclusive creation * semantics, try again with simple 'guarded' mode. */ switch (data->arg.create.createmode) { case NFS3_CREATE_EXCLUSIVE: data->arg.create.createmode = NFS3_CREATE_GUARDED; break; case NFS3_CREATE_GUARDED: data->arg.create.createmode = NFS3_CREATE_UNCHECKED; break; case NFS3_CREATE_UNCHECKED: goto out; } nfs_fattr_init(data->res.dir_attr); nfs_fattr_init(data->res.fattr); } if (status != 0) goto out_release_acls; /* When we created the file with exclusive semantics, make * sure we set the attributes afterwards. */ if (data->arg.create.createmode == NFS3_CREATE_EXCLUSIVE) { dprintk("NFS call setattr (post-create)\n"); if (!(sattr->ia_valid & ATTR_ATIME_SET)) sattr->ia_valid |= ATTR_ATIME; if (!(sattr->ia_valid & ATTR_MTIME_SET)) sattr->ia_valid |= ATTR_MTIME; /* Note: we could use a guarded setattr here, but I'm * not sure this buys us anything (and I'd have * to revamp the NFSv3 XDR code) */ status = nfs3_proc_setattr(dentry, data->res.fattr, sattr); nfs_post_op_update_inode(dentry->d_inode, data->res.fattr); dprintk("NFS reply setattr (post-create): %d\n", status); if (status != 0) goto out_release_acls; } status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl); out_release_acls: posix_acl_release(acl); posix_acl_release(default_acl); out: nfs3_free_createdata(data); dprintk("NFS reply create: %d\n", status); return status; }
STATIC int xfs_vn_mknod( struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { struct inode *inode; struct xfs_inode *ip = NULL; struct posix_acl *default_acl, *acl; struct xfs_name name; int error; /* * Irix uses Missed'em'V split, but doesn't want to see * the upper 5 bits of (14bit) major. */ if (S_ISCHR(mode) || S_ISBLK(mode)) { if (unlikely(!sysv_valid_dev(rdev) || MAJOR(rdev) & ~0x1ff)) return -EINVAL; rdev = sysv_encode_dev(rdev); } else { rdev = 0; } error = posix_acl_create(dir, &mode, &default_acl, &acl); if (error) return error; xfs_dentry_to_name(&name, dentry, mode); error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip); if (unlikely(error)) goto out_free_acl; inode = VFS_I(ip); error = xfs_init_security(inode, dir, &dentry->d_name); if (unlikely(error)) goto out_cleanup_inode; #ifdef CONFIG_XFS_POSIX_ACL if (default_acl) { error = xfs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); if (error) goto out_cleanup_inode; } if (acl) { error = xfs_set_acl(inode, acl, ACL_TYPE_ACCESS); if (error) goto out_cleanup_inode; } #endif d_instantiate(dentry, inode); out_free_acl: if (default_acl) posix_acl_release(default_acl); if (acl) posix_acl_release(acl); return -error; out_cleanup_inode: xfs_cleanup_inode(dir, inode, dentry); goto out_free_acl; }
static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, struct gfs2_inode *ip, struct gfs2_diradd *da) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_alloc_parms ap = { .target = da->nr_blocks, }; int error; if (da->nr_blocks) { error = gfs2_quota_lock_check(dip); if (error) goto fail_quota_locks; error = gfs2_inplace_reserve(dip, &ap); if (error) goto fail_quota_locks; error = gfs2_trans_begin(sdp, gfs2_trans_da_blks(dip, da, 2), 0); if (error) goto fail_ipreserv; } else { error = gfs2_trans_begin(sdp, RES_LEAF + 2 * RES_DINODE, 0); if (error) goto fail_quota_locks; } error = gfs2_dir_add(&dip->i_inode, name, ip, da); if (error) goto fail_end_trans; fail_end_trans: gfs2_trans_end(sdp); fail_ipreserv: gfs2_inplace_release(dip); fail_quota_locks: gfs2_quota_unlock(dip); return error; } static int gfs2_initxattrs(struct inode *inode, const struct xattr *xattr_array, void *fs_info) { const struct xattr *xattr; int err = 0; for (xattr = xattr_array; xattr->name != NULL; xattr++) { err = __gfs2_xattr_set(inode, xattr->name, xattr->value, xattr->value_len, 0, GFS2_EATYPE_SECURITY); if (err < 0) break; } return err; } static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip, const struct qstr *qstr) { return security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr, &gfs2_initxattrs, NULL); } /** * gfs2_create_inode - Create a new inode * @dir: The parent directory * @dentry: The new dentry * @file: If non-NULL, the file which is being opened * @mode: The permissions on the new inode * @dev: For device nodes, this is the device number * @symname: For symlinks, this is the link destination * @size: The initial size of the inode (ignored for directories) * * Returns: 0 on success, or error code */ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, struct file *file, umode_t mode, dev_t dev, const char *symname, unsigned int size, int excl, int *opened) { const struct qstr *name = &dentry->d_name; struct posix_acl *default_acl, *acl; struct gfs2_holder ghs[2]; struct inode *inode = NULL; struct gfs2_inode *dip = GFS2_I(dir), *ip; struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_glock *io_gl; struct dentry *d; int error; u32 aflags = 0; struct gfs2_diradd da = { .bh = NULL, }; if (!name->len || name->len > GFS2_FNAMESIZE) return -ENAMETOOLONG; error = gfs2_rs_alloc(dip); if (error) return error; error = gfs2_rindex_update(sdp); if (error) return error; error = gfs2_glock_nq_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); if (error) goto fail; error = create_ok(dip, name, mode); if (error) goto fail_gunlock; inode = gfs2_dir_search(dir, &dentry->d_name, !S_ISREG(mode) || excl); error = PTR_ERR(inode); if (!IS_ERR(inode)) { d = d_splice_alias(inode, dentry); error = PTR_ERR(d); if (IS_ERR(d)) { inode = ERR_CAST(d); goto fail_gunlock; } error = 0; if (file) { if (S_ISREG(inode->i_mode)) { WARN_ON(d != NULL); error = finish_open(file, dentry, gfs2_open_common, opened); } else { error = finish_no_open(file, d); } } else { dput(d); } gfs2_glock_dq_uninit(ghs); return error; } else if (error != -ENOENT) { goto fail_gunlock; } error = gfs2_diradd_alloc_required(dir, name, &da); if (error < 0) goto fail_gunlock; inode = new_inode(sdp->sd_vfs); error = -ENOMEM; if (!inode) goto fail_gunlock; error = posix_acl_create(dir, &mode, &default_acl, &acl); if (error) goto fail_free_vfs_inode; ip = GFS2_I(inode); error = gfs2_rs_alloc(ip); if (error) goto fail_free_acls; inode->i_mode = mode; set_nlink(inode, S_ISDIR(mode) ? 2 : 1); inode->i_rdev = dev; inode->i_size = size; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; gfs2_set_inode_blocks(inode, 1); munge_mode_uid_gid(dip, inode); ip->i_goal = dip->i_goal; ip->i_diskflags = 0; ip->i_eattr = 0; ip->i_height = 0; ip->i_depth = 0; ip->i_entries = 0; switch(mode & S_IFMT) { case S_IFREG: if ((dip->i_diskflags & GFS2_DIF_INHERIT_JDATA) || gfs2_tune_get(sdp, gt_new_files_jdata)) ip->i_diskflags |= GFS2_DIF_JDATA; gfs2_set_aops(inode); break; case S_IFDIR: ip->i_diskflags |= (dip->i_diskflags & GFS2_DIF_INHERIT_JDATA); ip->i_diskflags |= GFS2_DIF_JDATA; ip->i_entries = 2; break; } gfs2_set_inode_flags(inode); if ((GFS2_I(sdp->sd_root_dir->d_inode) == dip) || (dip->i_diskflags & GFS2_DIF_TOPDIR)) aflags |= GFS2_AF_ORLOV; error = alloc_dinode(ip, aflags); if (error) goto fail_free_inode; error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl); if (error) goto fail_free_inode; ip->i_gl->gl_object = ip; error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1); if (error) goto fail_free_inode; error = gfs2_trans_begin(sdp, RES_DINODE, 0); if (error) goto fail_gunlock2; init_dinode(dip, ip, symname); gfs2_trans_end(sdp); error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_iopen_glops, CREATE, &io_gl); if (error) goto fail_gunlock2; error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh); if (error) goto fail_gunlock2; ip->i_iopen_gh.gh_gl->gl_object = ip; gfs2_glock_put(io_gl); gfs2_set_iop(inode); insert_inode_hash(inode); if (default_acl) { error = gfs2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); posix_acl_release(default_acl); } if (acl) { if (!error) error = gfs2_set_acl(inode, acl, ACL_TYPE_ACCESS); posix_acl_release(acl); } if (error) goto fail_gunlock3; error = gfs2_security_init(dip, ip, name); if (error) goto fail_gunlock3; error = link_dinode(dip, name, ip, &da); if (error) goto fail_gunlock3; mark_inode_dirty(inode); d_instantiate(dentry, inode); if (file) { *opened |= FILE_CREATED; error = finish_open(file, dentry, gfs2_open_common, opened); } gfs2_glock_dq_uninit(ghs); gfs2_glock_dq_uninit(ghs + 1); return error; fail_gunlock3: gfs2_glock_dq_uninit(ghs + 1); if (ip->i_gl) gfs2_glock_put(ip->i_gl); goto fail_gunlock; fail_gunlock2: gfs2_glock_dq_uninit(ghs + 1); fail_free_inode: if (ip->i_gl) gfs2_glock_put(ip->i_gl); gfs2_rs_delete(ip, NULL); fail_free_acls: if (default_acl) posix_acl_release(default_acl); if (acl) posix_acl_release(acl); fail_free_vfs_inode: free_inode_nonrcu(inode); inode = NULL; fail_gunlock: gfs2_dir_no_add(&da); gfs2_glock_dq_uninit(ghs); if (inode && !IS_ERR(inode)) { clear_nlink(inode); mark_inode_dirty(inode); set_bit(GIF_ALLOC_FAILED, &GFS2_I(inode)->i_flags); iput(inode); } fail: return error; } /** * gfs2_create - Create a file * @dir: The directory in which to create the file * @dentry: The dentry of the new file * @mode: The mode of the new file * * Returns: errno */ static int gfs2_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { return gfs2_create_inode(dir, dentry, NULL, S_IFREG | mode, 0, NULL, 0, excl, NULL); } /** * __gfs2_lookup - Look up a filename in a directory and return its inode * @dir: The directory inode * @dentry: The dentry of the new inode * @file: File to be opened * @opened: atomic_open flags * * * Returns: errno */ static struct dentry *__gfs2_lookup(struct inode *dir, struct dentry *dentry, struct file *file, int *opened) { struct inode *inode; struct dentry *d; struct gfs2_holder gh; struct gfs2_glock *gl; int error; inode = gfs2_lookupi(dir, &dentry->d_name, 0); if (!inode) return NULL; if (IS_ERR(inode)) return ERR_CAST(inode); gl = GFS2_I(inode)->i_gl; error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); if (error) { iput(inode); return ERR_PTR(error); } d = d_splice_alias(inode, dentry); if (IS_ERR(d)) { gfs2_glock_dq_uninit(&gh); return d; } if (file && S_ISREG(inode->i_mode)) error = finish_open(file, dentry, gfs2_open_common, opened); gfs2_glock_dq_uninit(&gh); if (error) { dput(d); return ERR_PTR(error); } return d; } static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, unsigned flags) { return __gfs2_lookup(dir, dentry, NULL, NULL); } /** * gfs2_link - Link to a file * @old_dentry: The inode to link * @dir: Add link to this directory * @dentry: The name of the link * * Link the inode in "old_dentry" into the directory "dir" with the * name in "dentry". * * Returns: errno */ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_sbd *sdp = GFS2_SB(dir); struct inode *inode = old_dentry->d_inode; struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder ghs[2]; struct buffer_head *dibh; struct gfs2_diradd da = { .bh = NULL, }; int error; if (S_ISDIR(inode->i_mode)) return -EPERM; error = gfs2_rs_alloc(dip); if (error) return error; gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); error = gfs2_glock_nq(ghs); /* parent */ if (error) goto out_parent; error = gfs2_glock_nq(ghs + 1); /* child */ if (error) goto out_child; error = -ENOENT; if (inode->i_nlink == 0) goto out_gunlock; error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC); if (error) goto out_gunlock; error = gfs2_dir_check(dir, &dentry->d_name, NULL); switch (error) { case -ENOENT: break; case 0: error = -EEXIST; default: goto out_gunlock; } error = -EINVAL; if (!dip->i_inode.i_nlink) goto out_gunlock; error = -EFBIG; if (dip->i_entries == (u32)-1) goto out_gunlock; error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto out_gunlock; error = -EINVAL; if (!ip->i_inode.i_nlink) goto out_gunlock; error = -EMLINK; if (ip->i_inode.i_nlink == (u32)-1) goto out_gunlock; error = gfs2_diradd_alloc_required(dir, &dentry->d_name, &da); if (error < 0) goto out_gunlock; if (da.nr_blocks) { struct gfs2_alloc_parms ap = { .target = da.nr_blocks, }; error = gfs2_quota_lock_check(dip); if (error) goto out_gunlock; error = gfs2_inplace_reserve(dip, &ap); if (error) goto out_gunlock_q; error = gfs2_trans_begin(sdp, gfs2_trans_da_blks(dip, &da, 2), 0); if (error) goto out_ipres; } else { error = gfs2_trans_begin(sdp, 2 * RES_DINODE + RES_LEAF, 0); if (error) goto out_ipres; } error = gfs2_meta_inode_buffer(ip, &dibh); if (error) goto out_end_trans; error = gfs2_dir_add(dir, &dentry->d_name, ip, &da); if (error) goto out_brelse; gfs2_trans_add_meta(ip->i_gl, dibh); inc_nlink(&ip->i_inode); ip->i_inode.i_ctime = CURRENT_TIME; ihold(inode); d_instantiate(dentry, inode); mark_inode_dirty(inode); out_brelse: brelse(dibh); out_end_trans: gfs2_trans_end(sdp); out_ipres: if (da.nr_blocks) gfs2_inplace_release(dip); out_gunlock_q: if (da.nr_blocks) gfs2_quota_unlock(dip); out_gunlock: gfs2_dir_no_add(&da); gfs2_glock_dq(ghs + 1); out_child: gfs2_glock_dq(ghs); out_parent: gfs2_holder_uninit(ghs); gfs2_holder_uninit(ghs + 1); return error; } /* * gfs2_unlink_ok - check to see that a inode is still in a directory * @dip: the directory * @name: the name of the file * @ip: the inode * * Assumes that the lock on (at least) @dip is held. * * Returns: 0 if the parent/child relationship is correct, errno if it isn't */ static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name, const struct gfs2_inode *ip) { int error; if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode)) return -EPERM; if ((dip->i_inode.i_mode & S_ISVTX) && !uid_eq(dip->i_inode.i_uid, current_fsuid()) && !uid_eq(ip->i_inode.i_uid, current_fsuid()) && !capable(CAP_FOWNER)) return -EPERM; if (IS_APPEND(&dip->i_inode)) return -EPERM; error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC); if (error) return error; error = gfs2_dir_check(&dip->i_inode, name, ip); if (error) return error; return 0; }
static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, struct ovl_cattr *cattr) { struct dentry *workdir = ovl_workdir(dentry); struct inode *wdir = workdir->d_inode; struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent); struct inode *udir = upperdir->d_inode; struct dentry *upper; struct dentry *newdentry; int err; struct posix_acl *acl, *default_acl; bool hardlink = !!cattr->hardlink; if (WARN_ON(!workdir)) return -EROFS; if (!hardlink) { err = posix_acl_create(dentry->d_parent->d_inode, &cattr->mode, &default_acl, &acl); if (err) return err; } err = ovl_lock_rename_workdir(workdir, upperdir); if (err) goto out; upper = lookup_one_len(dentry->d_name.name, upperdir, dentry->d_name.len); err = PTR_ERR(upper); if (IS_ERR(upper)) goto out_unlock; newdentry = ovl_create_temp(workdir, cattr); err = PTR_ERR(newdentry); if (IS_ERR(newdentry)) goto out_dput; /* * mode could have been mutilated due to umask (e.g. sgid directory) */ if (!hardlink && !S_ISLNK(cattr->mode) && newdentry->d_inode->i_mode != cattr->mode) { struct iattr attr = { .ia_valid = ATTR_MODE, .ia_mode = cattr->mode, }; inode_lock(newdentry->d_inode); err = notify_change(newdentry, &attr, NULL); inode_unlock(newdentry->d_inode); if (err) goto out_cleanup; } if (!hardlink) { err = ovl_set_upper_acl(newdentry, XATTR_NAME_POSIX_ACL_ACCESS, acl); if (err) goto out_cleanup; err = ovl_set_upper_acl(newdentry, XATTR_NAME_POSIX_ACL_DEFAULT, default_acl); if (err) goto out_cleanup; } if (!hardlink && S_ISDIR(cattr->mode)) { err = ovl_set_opaque(dentry, newdentry); if (err) goto out_cleanup; err = ovl_do_rename(wdir, newdentry, udir, upper, RENAME_EXCHANGE); if (err) goto out_cleanup; ovl_cleanup(wdir, upper); } else { err = ovl_do_rename(wdir, newdentry, udir, upper, 0); if (err) goto out_cleanup; } err = ovl_instantiate(dentry, inode, newdentry, hardlink); if (err) goto out_cleanup; out_dput: dput(upper); out_unlock: unlock_rename(workdir, upperdir); out: if (!hardlink) { posix_acl_release(acl); posix_acl_release(default_acl); } return err; out_cleanup: ovl_cleanup(wdir, newdentry); dput(newdentry); goto out_dput; } static int ovl_create_or_link(struct dentry *dentry, struct inode *inode, struct ovl_cattr *attr, bool origin) { int err; const struct cred *old_cred; struct cred *override_cred; struct dentry *parent = dentry->d_parent; err = ovl_copy_up(parent); if (err) return err; old_cred = ovl_override_creds(dentry->d_sb); /* * When linking a file with copy up origin into a new parent, mark the * new parent dir "impure". */ if (origin) { err = ovl_set_impure(parent, ovl_dentry_upper(parent)); if (err) goto out_revert_creds; } err = -ENOMEM; override_cred = prepare_creds(); if (override_cred) { override_cred->fsuid = inode->i_uid; override_cred->fsgid = inode->i_gid; if (!attr->hardlink) { err = security_dentry_create_files_as(dentry, attr->mode, &dentry->d_name, old_cred, override_cred); if (err) { put_cred(override_cred); goto out_revert_creds; } } put_cred(override_creds(override_cred)); put_cred(override_cred); if (!ovl_dentry_is_whiteout(dentry)) err = ovl_create_upper(dentry, inode, attr); else err = ovl_create_over_whiteout(dentry, inode, attr); } out_revert_creds: revert_creds(old_cred); return err; }
int ceph_pre_init_acls(struct inode *dir, umode_t *mode, struct ceph_acls_info *info) { struct posix_acl *acl, *default_acl; size_t val_size1 = 0, val_size2 = 0; struct ceph_pagelist *pagelist = NULL; void *tmp_buf = NULL; int err; err = posix_acl_create(dir, mode, &default_acl, &acl); if (err) return err; if (acl) { int ret = posix_acl_equiv_mode(acl, mode); if (ret < 0) goto out_err; if (ret == 0) { posix_acl_release(acl); acl = NULL; } } if (!default_acl && !acl) return 0; if (acl) val_size1 = posix_acl_xattr_size(acl->a_count); if (default_acl) val_size2 = posix_acl_xattr_size(default_acl->a_count); err = -ENOMEM; tmp_buf = kmalloc(max(val_size1, val_size2), GFP_KERNEL); if (!tmp_buf) goto out_err; pagelist = kmalloc(sizeof(struct ceph_pagelist), GFP_KERNEL); if (!pagelist) goto out_err; ceph_pagelist_init(pagelist); err = ceph_pagelist_reserve(pagelist, PAGE_SIZE); if (err) goto out_err; ceph_pagelist_encode_32(pagelist, acl && default_acl ? 2 : 1); if (acl) { size_t len = strlen(XATTR_NAME_POSIX_ACL_ACCESS); err = ceph_pagelist_reserve(pagelist, len + val_size1 + 8); if (err) goto out_err; ceph_pagelist_encode_string(pagelist, XATTR_NAME_POSIX_ACL_ACCESS, len); err = posix_acl_to_xattr(&init_user_ns, acl, tmp_buf, val_size1); if (err < 0) goto out_err; ceph_pagelist_encode_32(pagelist, val_size1); ceph_pagelist_append(pagelist, tmp_buf, val_size1); } if (default_acl) { size_t len = strlen(XATTR_NAME_POSIX_ACL_DEFAULT); err = ceph_pagelist_reserve(pagelist, len + val_size2 + 8); if (err) goto out_err; err = ceph_pagelist_encode_string(pagelist, XATTR_NAME_POSIX_ACL_DEFAULT, len); err = posix_acl_to_xattr(&init_user_ns, default_acl, tmp_buf, val_size2); if (err < 0) goto out_err; ceph_pagelist_encode_32(pagelist, val_size2); ceph_pagelist_append(pagelist, tmp_buf, val_size2); } kfree(tmp_buf); info->acl = acl; info->default_acl = default_acl; info->pagelist = pagelist; return 0; out_err: posix_acl_release(acl); posix_acl_release(default_acl); kfree(tmp_buf); if (pagelist) ceph_pagelist_release(pagelist); return err; }