/* * 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; mode_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) { struct posix_acl *clone; 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; } clone = posix_acl_clone(acl, GFP_NOFS); ret = -ENOMEM; if (!clone) goto cleanup; mode = inode->i_mode; ret = posix_acl_create_masq(clone, &mode); if (ret >= 0) { ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode); if (ret > 0) { ret = ocfs2_set_acl(handle, inode, di_bh, ACL_TYPE_ACCESS, clone, meta_ac, data_ac); } } posix_acl_release(clone); } cleanup: posix_acl_release(acl); return ret; }
static int ocfs2_block_group_search(struct inode *inode, struct buffer_head *group_bh, u32 bits_wanted, u32 min_bits, u64 max_block, u16 *bit_off, u16 *bits_found) { int ret = -ENOSPC; u64 blkoff; struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) group_bh->b_data; BUG_ON(min_bits != 1); BUG_ON(ocfs2_is_cluster_bitmap(inode)); if (bg->bg_free_bits_count) { ret = ocfs2_block_group_find_clear_bits(OCFS2_SB(inode->i_sb), group_bh, bits_wanted, le16_to_cpu(bg->bg_bits), bit_off, bits_found); if (!ret && max_block) { blkoff = le64_to_cpu(bg->bg_blkno) + *bit_off + *bits_found; mlog(0, "Checking %llu against %llu\n", (unsigned long long)blkoff, (unsigned long long)max_block); if (blkoff > max_block) ret = -ENOSPC; } } return ret; }
int ocfs2_info_handle_fs_features(struct inode *inode, struct ocfs2_info_request __user *req) { int status = -EFAULT; struct ocfs2_info_fs_features oif; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); if (o2info_from_user(oif, req)) goto bail; oif.if_compat_features = osb->s_feature_compat; oif.if_incompat_features = osb->s_feature_incompat; oif.if_ro_compat_features = osb->s_feature_ro_compat; o2info_set_request_filled(&oif.if_req); if (o2info_to_user(oif, req)) goto bail; status = 0; bail: if (status) o2info_set_request_error(&oif.if_req, req); return status; }
void ocfs2_compute_meta_ecc_bhs(struct super_block *sb, struct buffer_head **bhs, int nr, struct ocfs2_block_check *bc) { if (ocfs2_meta_ecc(OCFS2_SB(sb))) ocfs2_block_check_compute_bhs(bhs, nr, bc); }
static struct dentry *ocfs2_get_dentry(struct super_block *sb, struct ocfs2_inode_handle *handle) { struct inode *inode; struct dentry *result; mlog_entry("(0x%p, 0x%p)\n", sb, handle); if (handle->ih_blkno == 0) { mlog_errno(-ESTALE); return ERR_PTR(-ESTALE); } inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno, 0, 0); if (IS_ERR(inode)) return (void *)inode; if (handle->ih_generation != inode->i_generation) { iput(inode); return ERR_PTR(-ESTALE); } result = d_alloc_anon(inode); if (!result) { iput(inode); mlog_errno(-ENOMEM); return ERR_PTR(-ENOMEM); } result->d_op = &ocfs2_dentry_ops; mlog_exit_ptr(result); return result; }
handle_t *ocfs2_start_walk_page_trans(struct inode *inode, struct page *page, unsigned from, unsigned to) { struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); handle_t *handle; int ret = 0; handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); if (IS_ERR(handle)) { ret = -ENOMEM; mlog_errno(ret); goto out; } if (ocfs2_should_order_data(inode)) { ret = walk_page_buffers(handle, page_buffers(page), from, to, NULL, ocfs2_journal_dirty_data); if (ret < 0) mlog_errno(ret); } out: if (ret) { if (!IS_ERR(handle)) ocfs2_commit_trans(osb, handle); handle = ERR_PTR(ret); } return handle; }
int ocfs2_mmap(struct file *file, struct vm_area_struct *vma) { int ret = 0, lock_level = 0; struct ocfs2_super *osb = OCFS2_SB(file->f_dentry->d_inode->i_sb); /* * Only support shared writeable mmap for local mounts which * don't know about holes. */ if ((!ocfs2_mount_local(osb) || ocfs2_sparse_alloc(osb)) && ((vma->vm_flags & VM_SHARED) || (vma->vm_flags & VM_MAYSHARE)) && ((vma->vm_flags & VM_WRITE) || (vma->vm_flags & VM_MAYWRITE))) { mlog(0, "disallow shared writable mmaps %lx\n", vma->vm_flags); /* This is -EINVAL because generic_file_readonly_mmap * returns it in a similar situation. */ return -EINVAL; } ret = ocfs2_meta_lock_atime(file->f_dentry->d_inode, file->f_vfsmnt, &lock_level); if (ret < 0) { mlog_errno(ret); goto out; } ocfs2_meta_unlock(file->f_dentry->d_inode, lock_level); out: vma->vm_ops = &ocfs2_file_vm_ops; vma->vm_flags |= VM_CAN_NONLINEAR; return 0; }
static int ocfs2_xattr_set_acl(struct dentry *dentry, const char *name, const void *value, size_t size, int flags, int type) { struct inode *inode = dentry->d_inode; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct posix_acl *acl; int ret = 0; if (strcmp(name, "") != 0) return -EINVAL; if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) return -EOPNOTSUPP; if (!is_owner_or_cap(inode)) return -EPERM; if (value) { acl = posix_acl_from_xattr(value, size); if (IS_ERR(acl)) return PTR_ERR(acl); else if (acl) { ret = posix_acl_valid(acl); if (ret) goto cleanup; } } else acl = NULL; ret = ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL); cleanup: posix_acl_release(acl); return ret; }
static char *ocfs2_fast_symlink_getlink(struct inode *inode, struct buffer_head **bh) { int status; char *link = NULL; struct ocfs2_dinode *fe; mlog_entry_void(); status = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno, bh, OCFS2_BH_CACHED, inode); if (status < 0) { mlog_errno(status); link = ERR_PTR(status); goto bail; } fe = (struct ocfs2_dinode *) (*bh)->b_data; link = (char *) fe->id2.i_symlink; bail: mlog_exit(status); return link; }
int ocfs2_check_acl(struct inode *inode, int mask) { struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct buffer_head *di_bh = NULL; struct posix_acl *acl; int ret = -EAGAIN; if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) return ret; ret = ocfs2_read_inode_block(inode, &di_bh); if (ret < 0) { mlog_errno(ret); return ret; } acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, di_bh); brelse(di_bh); if (IS_ERR(acl)) { mlog_errno(PTR_ERR(acl)); return PTR_ERR(acl); } if (acl) { ret = posix_acl_permission(inode, acl, mask); posix_acl_release(acl); return ret; } return -EAGAIN; }
static struct dentry *ocfs2_get_parent(struct dentry *child) { int status; u64 blkno; struct dentry *parent; struct inode *dir = child->d_inode; trace_ocfs2_get_parent(child, child->d_name.len, child->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno); status = ocfs2_inode_lock(dir, NULL, 0); if (status < 0) { if (status != -ENOENT) mlog_errno(status); parent = ERR_PTR(status); goto bail; } status = ocfs2_lookup_ino_from_name(dir, "..", 2, &blkno); if (status < 0) { parent = ERR_PTR(-ENOENT); goto bail_unlock; } parent = d_obtain_alias(ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0)); bail_unlock: ocfs2_inode_unlock(dir, 0); bail: trace_ocfs2_get_parent_end(parent); return parent; }
/* * Get posix acl. */ static struct posix_acl *ocfs2_get_acl(struct inode *inode, int type) { struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct buffer_head *di_bh = NULL; struct posix_acl *acl; int ret; if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) return NULL; ret = ocfs2_inode_lock(inode, &di_bh, 0); if (ret < 0) { mlog_errno(ret); acl = ERR_PTR(ret); return acl; } acl = ocfs2_get_acl_nolock(inode, type, di_bh); ocfs2_inode_unlock(inode, 0); brelse(di_bh); return acl; }
int ocfs2_acl_chmod(struct inode *inode) { struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct posix_acl *acl, *clone; int ret; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) return 0; acl = ocfs2_get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl) || !acl) return PTR_ERR(acl); clone = posix_acl_clone(acl, GFP_KERNEL); posix_acl_release(acl); if (!clone) return -ENOMEM; ret = posix_acl_chmod_masq(clone, inode->i_mode); if (!ret) ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS, clone, NULL, NULL); posix_acl_release(clone); return ret; }
static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac, handle_t *handle, u32 bits_wanted, u32 min_bits, u16 *bit_off, unsigned int *num_bits, u64 gd_blkno, u16 *bits_left) { int ret; u16 found; struct buffer_head *group_bh = NULL; struct ocfs2_group_desc *gd; struct inode *alloc_inode = ac->ac_inode; ret = ocfs2_read_block(OCFS2_SB(alloc_inode->i_sb), gd_blkno, &group_bh, OCFS2_BH_CACHED, alloc_inode); if (ret < 0) { mlog_errno(ret); return ret; } gd = (struct ocfs2_group_desc *) group_bh->b_data; if (!OCFS2_IS_VALID_GROUP_DESC(gd)) { OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, gd); ret = -EIO; goto out; } ret = ac->ac_group_search(alloc_inode, group_bh, bits_wanted, min_bits, bit_off, &found); if (ret < 0) { if (ret != -ENOSPC) mlog_errno(ret); goto out; } *num_bits = found; ret = ocfs2_alloc_dinode_update_counts(alloc_inode, handle, ac->ac_bh, *num_bits, le16_to_cpu(gd->bg_chain)); if (ret < 0) { mlog_errno(ret); goto out; } ret = ocfs2_block_group_set_bits(handle, alloc_inode, gd, group_bh, *bit_off, *num_bits); if (ret < 0) mlog_errno(ret); *bits_left = le16_to_cpu(gd->bg_free_bits_count); out: brelse(group_bh); return ret; }
static struct dentry *ocfs2_get_parent(struct dentry *child) { int status; u64 blkno; struct dentry *parent; struct inode *inode; struct inode *dir = child->d_inode; struct buffer_head *dirent_bh = NULL; struct ocfs2_dir_entry *dirent; mlog_entry("(0x%p, '%.*s')\n", child, child->d_name.len, child->d_name.name); mlog(0, "find parent of directory %llu\n", (unsigned long long)OCFS2_I(dir)->ip_blkno); status = ocfs2_meta_lock(dir, NULL, 0); if (status < 0) { if (status != -ENOENT) mlog_errno(status); parent = ERR_PTR(status); goto bail; } status = ocfs2_find_files_on_disk("..", 2, &blkno, dir, &dirent_bh, &dirent); if (status < 0) { parent = ERR_PTR(-ENOENT); goto bail_unlock; } inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0); if (IS_ERR(inode)) { mlog(ML_ERROR, "Unable to create inode %llu\n", (unsigned long long)blkno); parent = ERR_PTR(-EACCES); goto bail_unlock; } parent = d_alloc_anon(inode); if (!parent) { iput(inode); parent = ERR_PTR(-ENOMEM); } parent->d_op = &ocfs2_dentry_ops; bail_unlock: ocfs2_meta_unlock(dir, 0); if (dirent_bh) brelse(dirent_bh); bail: mlog_exit_ptr(parent); return parent; }
int ocfs2_journal_access(handle_t *handle, struct inode *inode, struct buffer_head *bh, int type) { int status; BUG_ON(!inode); BUG_ON(!handle); BUG_ON(!bh); mlog_entry("bh->b_blocknr=%llu, type=%d (\"%s\"), bh->b_size = %zu\n", (unsigned long long)bh->b_blocknr, type, (type == OCFS2_JOURNAL_ACCESS_CREATE) ? "OCFS2_JOURNAL_ACCESS_CREATE" : "OCFS2_JOURNAL_ACCESS_WRITE", bh->b_size); /* we can safely remove this assertion after testing. */ if (!buffer_uptodate(bh)) { mlog(ML_ERROR, "giving me a buffer that's not uptodate!\n"); mlog(ML_ERROR, "b_blocknr=%llu\n", (unsigned long long)bh->b_blocknr); BUG(); } /* Set the current transaction information on the inode so * that the locking code knows whether it can drop it's locks * on this inode or not. We're protected from the commit * thread updating the current transaction id until * ocfs2_commit_trans() because ocfs2_start_trans() took * j_trans_barrier for us. */ ocfs2_set_inode_lock_trans(OCFS2_SB(inode->i_sb)->journal, inode); mutex_lock(&OCFS2_I(inode)->ip_io_mutex); switch (type) { case OCFS2_JOURNAL_ACCESS_CREATE: case OCFS2_JOURNAL_ACCESS_WRITE: status = journal_get_write_access(handle, bh); break; case OCFS2_JOURNAL_ACCESS_UNDO: status = journal_get_undo_access(handle, bh); break; default: status = -EINVAL; mlog(ML_ERROR, "Uknown access type!\n"); } mutex_unlock(&OCFS2_I(inode)->ip_io_mutex); if (status < 0) mlog(ML_ERROR, "Error %d getting %d access to buffer!\n", status, type); mlog_exit(status); return status; }
/* Some parts of this taken from generic_cont_expand, which turned out * to be too fragile to do exactly what we need without us having to * worry about recursive locking in ->write_begin() and ->write_end(). */ static int ocfs2_write_zero_page(struct inode *inode, u64 size) { struct address_space *mapping = inode->i_mapping; struct page *page; unsigned long index; unsigned int offset; handle_t *handle = NULL; int ret; offset = (size & (PAGE_CACHE_SIZE-1)); /* Within page */ /* ugh. in prepare/commit_write, if from==to==start of block, we ** skip the prepare. make sure we never send an offset for the start ** of a block */ if ((offset & (inode->i_sb->s_blocksize - 1)) == 0) { offset++; } index = size >> PAGE_CACHE_SHIFT; page = grab_cache_page(mapping, index); if (!page) { ret = -ENOMEM; mlog_errno(ret); goto out; } ret = ocfs2_prepare_write_nolock(inode, page, offset, offset); if (ret < 0) { mlog_errno(ret); goto out_unlock; } if (ocfs2_should_order_data(inode)) { handle = ocfs2_start_walk_page_trans(inode, page, offset, offset); if (IS_ERR(handle)) { ret = PTR_ERR(handle); handle = NULL; goto out_unlock; } } /* must not update i_size! */ ret = block_commit_write(page, offset, offset); if (ret < 0) mlog_errno(ret); else ret = 0; if (handle) ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); out_unlock: unlock_page(page); page_cache_release(page); out: return ret; }
static int ocfs2_block_group_fill(handle_t *handle, struct inode *alloc_inode, struct buffer_head *bg_bh, u64 group_blkno, u16 my_chain, struct ocfs2_chain_list *cl) { int status = 0; struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) bg_bh->b_data; struct super_block * sb = alloc_inode->i_sb; mlog_entry_void(); if (((unsigned long long) bg_bh->b_blocknr) != group_blkno) { ocfs2_error(alloc_inode->i_sb, "group block (%llu) != " "b_blocknr (%llu)", (unsigned long long)group_blkno, (unsigned long long) bg_bh->b_blocknr); status = -EIO; goto bail; } status = ocfs2_journal_access(handle, alloc_inode, bg_bh, OCFS2_JOURNAL_ACCESS_CREATE); if (status < 0) { mlog_errno(status); goto bail; } memset(bg, 0, sb->s_blocksize); strcpy(bg->bg_signature, OCFS2_GROUP_DESC_SIGNATURE); bg->bg_generation = cpu_to_le32(OCFS2_SB(sb)->fs_generation); bg->bg_size = cpu_to_le16(ocfs2_group_bitmap_size(sb)); bg->bg_bits = cpu_to_le16(ocfs2_bits_per_group(cl)); bg->bg_chain = cpu_to_le16(my_chain); bg->bg_next_group = cl->cl_recs[my_chain].c_blkno; bg->bg_parent_dinode = cpu_to_le64(OCFS2_I(alloc_inode)->ip_blkno); bg->bg_blkno = cpu_to_le64(group_blkno); /* set the 1st bit in the bitmap to account for the descriptor block */ ocfs2_set_bit(0, (unsigned long *)bg->bg_bitmap); bg->bg_free_bits_count = cpu_to_le16(le16_to_cpu(bg->bg_bits) - 1); status = ocfs2_journal_dirty(handle, bg_bh); if (status < 0) mlog_errno(status); /* There is no need to zero out or otherwise initialize the * other blocks in a group - All valid FS metadata in a block * group stores the superblock fs_generation value at * allocation time. */ bail: mlog_exit(status); return status; }
/* * XXX: helper to validate and adjust moving goal. */ static int ocfs2_validate_and_adjust_move_goal(struct inode *inode, struct ocfs2_move_extents *range) { int ret, goal_bit = 0; struct buffer_head *gd_bh = NULL; struct ocfs2_group_desc *bg; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); int c_to_b = 1 << (osb->s_clustersize_bits - inode->i_sb->s_blocksize_bits); /* * make goal become cluster aligned. */ range->me_goal = ocfs2_block_to_cluster_start(inode->i_sb, range->me_goal); /* * validate goal sits within global_bitmap, and return the victim * group desc */ ret = ocfs2_find_victim_alloc_group(inode, range->me_goal, GLOBAL_BITMAP_SYSTEM_INODE, OCFS2_INVALID_SLOT, &goal_bit, &gd_bh); if (ret) goto out; bg = (struct ocfs2_group_desc *)gd_bh->b_data; /* * moving goal is not allowd to start with a group desc blok(#0 blk) * let's compromise to the latter cluster. */ if (range->me_goal == le64_to_cpu(bg->bg_blkno)) range->me_goal += c_to_b; /* * movement is not gonna cross two groups. */ if ((le16_to_cpu(bg->bg_bits) - goal_bit) * osb->s_clustersize < range->me_len) { ret = -EINVAL; goto out; } /* * more exact validations/adjustments will be performed later during * moving operation for each extent range. */ mlog(0, "extents get ready to be moved to #%llu block\n", range->me_goal); out: brelse(gd_bh); return ret; }
int ocfs2_validate_meta_ecc(struct super_block *sb, void *data, struct ocfs2_block_check *bc) { int rc = 0; struct ocfs2_super *osb = OCFS2_SB(sb); if (ocfs2_meta_ecc(osb)) rc = ocfs2_block_check_validate(data, sb->s_blocksize, bc, &osb->osb_ecc_stats); return rc; }
/* * lock allocators, and reserving appropriate number of bits for * meta blocks and data clusters. * * in some cases, we don't need to reserve clusters, just let data_ac * be NULL. */ static int ocfs2_lock_allocators_move_extents(struct inode *inode, struct ocfs2_extent_tree *et, u32 clusters_to_move, u32 extents_to_split, struct ocfs2_alloc_context **meta_ac, struct ocfs2_alloc_context **data_ac, int extra_blocks, int *credits) { int ret, num_free_extents; unsigned int max_recs_needed = 2 * extents_to_split + clusters_to_move; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); num_free_extents = ocfs2_num_free_extents(osb, et); if (num_free_extents < 0) { ret = num_free_extents; mlog_errno(ret); goto out; } if (!num_free_extents || (ocfs2_sparse_alloc(osb) && num_free_extents < max_recs_needed)) extra_blocks += ocfs2_extend_meta_needed(et->et_root_el); ret = ocfs2_reserve_new_metadata_blocks(osb, extra_blocks, meta_ac); if (ret) { mlog_errno(ret); goto out; } if (data_ac) { ret = ocfs2_reserve_clusters(osb, clusters_to_move, data_ac); if (ret) { mlog_errno(ret); goto out; } } *credits += ocfs2_calc_extend_credits(osb->sb, et->et_root_el, clusters_to_move + 2); mlog(0, "reserve metadata_blocks: %d, data_clusters: %u, credits: %d\n", extra_blocks, clusters_to_move, *credits); out: if (ret) { if (*meta_ac) { ocfs2_free_alloc_context(*meta_ac); *meta_ac = NULL; } } return ret; }
/* return 0 on success, -ENOSPC to keep searching and any other < 0 * value on error. */ static int ocfs2_cluster_group_search(struct inode *inode, struct buffer_head *group_bh, u32 bits_wanted, u32 min_bits, u16 *bit_off, u16 *bits_found) { int search = -ENOSPC; int ret; struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *) group_bh->b_data; u16 tmp_off, tmp_found; unsigned int max_bits, gd_cluster_off; BUG_ON(!ocfs2_is_cluster_bitmap(inode)); if (gd->bg_free_bits_count) { max_bits = le16_to_cpu(gd->bg_bits); /* Tail groups in cluster bitmaps which aren't cpg * aligned are prone to partial extention by a failed * fs resize. If the file system resize never got to * update the dinode cluster count, then we don't want * to trust any clusters past it, regardless of what * the group descriptor says. */ gd_cluster_off = ocfs2_blocks_to_clusters(inode->i_sb, le64_to_cpu(gd->bg_blkno)); if ((gd_cluster_off + max_bits) > OCFS2_I(inode)->ip_clusters) { max_bits = OCFS2_I(inode)->ip_clusters - gd_cluster_off; mlog(0, "Desc %llu, bg_bits %u, clusters %u, use %u\n", (unsigned long long)le64_to_cpu(gd->bg_blkno), le16_to_cpu(gd->bg_bits), OCFS2_I(inode)->ip_clusters, max_bits); } ret = ocfs2_block_group_find_clear_bits(OCFS2_SB(inode->i_sb), group_bh, bits_wanted, max_bits, &tmp_off, &tmp_found); if (ret) return ret; /* ocfs2_block_group_find_clear_bits() might * return success, but we still want to return * -ENOSPC unless it found the minimum number * of bits. */ if (min_bits <= tmp_found) { *bit_off = tmp_off; *bits_found = tmp_found; search = 0; /* success */ } } return search; }
int ocfs2_validate_meta_ecc_bhs(struct super_block *sb, struct buffer_head **bhs, int nr, struct ocfs2_block_check *bc) { int rc = 0; struct ocfs2_super *osb = OCFS2_SB(sb); if (ocfs2_meta_ecc(osb)) rc = ocfs2_block_check_validate_bhs(bhs, nr, bc, &osb->osb_ecc_stats); return rc; }
/* * JBD Might read a cached version of another nodes journal file. We * don't want this as this file changes often and we get no * notification on those changes. The only way to be sure that we've * got the most up to date version of those blocks then is to force * read them off disk. Just searching through the buffer cache won't * work as there may be pages backing this file which are still marked * up to date. We know things can't change on this file underneath us * as we have the lock by now :) */ static int ocfs2_force_read_journal(struct inode *inode) { int status = 0; int i; u64 v_blkno, p_blkno, p_blocks, num_blocks; #define CONCURRENT_JOURNAL_FILL 32ULL struct buffer_head *bhs[CONCURRENT_JOURNAL_FILL]; mlog_entry_void(); memset(bhs, 0, sizeof(struct buffer_head *) * CONCURRENT_JOURNAL_FILL); num_blocks = ocfs2_blocks_for_bytes(inode->i_sb, inode->i_size); v_blkno = 0; while (v_blkno < num_blocks) { status = ocfs2_extent_map_get_blocks(inode, v_blkno, &p_blkno, &p_blocks, NULL); if (status < 0) { mlog_errno(status); goto bail; } if (p_blocks > CONCURRENT_JOURNAL_FILL) p_blocks = CONCURRENT_JOURNAL_FILL; /* We are reading journal data which should not * be put in the uptodate cache */ status = ocfs2_read_blocks(OCFS2_SB(inode->i_sb), p_blkno, p_blocks, bhs, 0, NULL); if (status < 0) { mlog_errno(status); goto bail; } for(i = 0; i < p_blocks; i++) { brelse(bhs[i]); bhs[i] = NULL; } v_blkno += p_blocks; } bail: for(i = 0; i < CONCURRENT_JOURNAL_FILL; i++) if (bhs[i]) brelse(bhs[i]); mlog_exit(status); return status; }
/* There is a series of simple checks that should be done before a * vote is even considered. Encapsulate those in this function. */ static int ocfs2_inode_is_valid_to_delete(struct inode *inode) { int ret = 0; struct ocfs2_inode_info *oi = OCFS2_I(inode); struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); /* We shouldn't be getting here for the root directory * inode.. */ if (inode == osb->root_inode) { mlog(ML_ERROR, "Skipping delete of root inode.\n"); goto bail; } /* If we're coming from process_vote we can't go into our own * voting [hello, deadlock city!], so unforuntately we just * have to skip deleting this guy. That's OK though because * the node who's doing the actual deleting should handle it * anyway. */ if (current == osb->vote_task) { mlog(0, "Skipping delete of %lu because we're currently " "in process_vote\n", inode->i_ino); goto bail; } spin_lock(&oi->ip_lock); /* OCFS2 *never* deletes system files. This should technically * never get here as system file inodes should always have a * positive link count. */ if (oi->ip_flags & OCFS2_INODE_SYSTEM_FILE) { mlog(ML_ERROR, "Skipping delete of system file %llu\n", (unsigned long long)oi->ip_blkno); goto bail_unlock; } /* If we have voted "yes" on the wipe of this inode for * another node, it will be marked here so we can safely skip * it. Recovery will cleanup any inodes we might inadvertantly * skip here. */ if (oi->ip_flags & OCFS2_INODE_SKIP_DELETE) { mlog(0, "Skipping delete of %lu because another node " "has done this for us.\n", inode->i_ino); goto bail_unlock; } ret = 1; bail_unlock: spin_unlock(&oi->ip_lock); bail: return ret; }
/* translate a group desc. blkno and it's bitmap offset into * disk cluster offset. */ static inline u32 ocfs2_desc_bitmap_to_cluster_off(struct inode *inode, u64 bg_blkno, u16 bg_bit_off) { struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); u32 cluster = 0; BUG_ON(!ocfs2_is_cluster_bitmap(inode)); if (bg_blkno != osb->first_cluster_group_blkno) cluster = ocfs2_blocks_to_clusters(inode->i_sb, bg_blkno); cluster += (u32) bg_bit_off; return cluster; }
static int ocfs2_write_remove_suid(struct inode *inode) { int ret; struct buffer_head *bh = NULL; struct ocfs2_inode_info *oi = OCFS2_I(inode); handle_t *handle; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct ocfs2_dinode *di; mlog_entry("(Inode %llu, mode 0%o)\n", (unsigned long long)oi->ip_blkno, inode->i_mode); handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); if (handle == NULL) { ret = -ENOMEM; mlog_errno(ret); goto out; } ret = ocfs2_read_block(osb, oi->ip_blkno, &bh, OCFS2_BH_CACHED, inode); if (ret < 0) { mlog_errno(ret); goto out_trans; } ret = ocfs2_journal_access(handle, inode, bh, OCFS2_JOURNAL_ACCESS_WRITE); if (ret < 0) { mlog_errno(ret); goto out_bh; } inode->i_mode &= ~S_ISUID; if ((inode->i_mode & S_ISGID) && (inode->i_mode & S_IXGRP)) inode->i_mode &= ~S_ISGID; di = (struct ocfs2_dinode *) bh->b_data; di->i_mode = cpu_to_le16(inode->i_mode); ret = ocfs2_journal_dirty(handle, bh); if (ret < 0) mlog_errno(ret); out_bh: brelse(bh); out_trans: ocfs2_commit_trans(osb, handle); out: mlog_exit(ret); return ret; }
/* given a cluster offset, calculate which block group it belongs to * and return that block offset. */ static inline u64 ocfs2_which_cluster_group(struct inode *inode, u32 cluster) { struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); u32 group_no; BUG_ON(!ocfs2_is_cluster_bitmap(inode)); group_no = cluster / osb->bitmap_cpg; if (!group_no) return osb->first_cluster_group_blkno; return ocfs2_clusters_to_blocks(inode->i_sb, group_no * osb->bitmap_cpg); }
static int __ocfs2_move_extents_range(struct buffer_head *di_bh, struct ocfs2_move_extents_context *context) { int ret = 0, flags, do_defrag, skip = 0; u32 cpos, phys_cpos, move_start, len_to_move, alloc_size; u32 len_defraged = 0, defrag_thresh = 0, new_phys_cpos = 0; struct inode *inode = context->inode; struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; struct ocfs2_move_extents *range = context->range; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); if ((inode->i_size == 0) || (range->me_len == 0)) return 0; if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) return 0; context->refcount_loc = le64_to_cpu(di->i_refcount_loc); ocfs2_init_dinode_extent_tree(&context->et, INODE_CACHE(inode), di_bh); ocfs2_init_dealloc_ctxt(&context->dealloc); /* * TO-DO XXX: * * - xattr extents. */ do_defrag = context->auto_defrag; /* * extents moving happens in unit of clusters, for the sake * of simplicity, we may ignore two clusters where 'byte_start' * and 'byte_start + len' were within. */ move_start = ocfs2_clusters_for_bytes(osb->sb, range->me_start); len_to_move = (range->me_start + range->me_len) >> osb->s_clustersize_bits; if (len_to_move >= move_start) len_to_move -= move_start; else len_to_move = 0; if (do_defrag) { defrag_thresh = range->me_threshold >> osb->s_clustersize_bits; if (defrag_thresh <= 1) goto done; } else
static int ocfs2_validate_gd_self(struct super_block *sb, struct buffer_head *bh, int resize) { struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *)bh->b_data; if (!OCFS2_IS_VALID_GROUP_DESC(gd)) { do_error("Group descriptor #%llu has bad signature %.*s", (unsigned long long)bh->b_blocknr, 7, gd->bg_signature); return -EINVAL; } if (le64_to_cpu(gd->bg_blkno) != bh->b_blocknr) { do_error("Group descriptor #%llu has an invalid bg_blkno " "of %llu", (unsigned long long)bh->b_blocknr, (unsigned long long)le64_to_cpu(gd->bg_blkno)); return -EINVAL; } if (le32_to_cpu(gd->bg_generation) != OCFS2_SB(sb)->fs_generation) { do_error("Group descriptor #%llu has an invalid " "fs_generation of #%u", (unsigned long long)bh->b_blocknr, le32_to_cpu(gd->bg_generation)); return -EINVAL; } if (le16_to_cpu(gd->bg_free_bits_count) > le16_to_cpu(gd->bg_bits)) { do_error("Group descriptor #%llu has bit count %u but " "claims that %u are free", (unsigned long long)bh->b_blocknr, le16_to_cpu(gd->bg_bits), le16_to_cpu(gd->bg_free_bits_count)); return -EINVAL; } if (le16_to_cpu(gd->bg_bits) > (8 * le16_to_cpu(gd->bg_size))) { do_error("Group descriptor #%llu has bit count %u but " "max bitmap bits of %u", (unsigned long long)bh->b_blocknr, le16_to_cpu(gd->bg_bits), 8 * le16_to_cpu(gd->bg_size)); return -EINVAL; } return 0; }