|
@@ -2185,3 +2185,162 @@ out:
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Read the inode specified by blkno to get suballoc_slot and
|
|
|
+ * suballoc_bit.
|
|
|
+ */
|
|
|
+static int ocfs2_get_suballoc_slot_bit(struct ocfs2_super *osb, u64 blkno,
|
|
|
+ u16 *suballoc_slot, u16 *suballoc_bit)
|
|
|
+{
|
|
|
+ int status;
|
|
|
+ struct buffer_head *inode_bh = NULL;
|
|
|
+ struct ocfs2_dinode *inode_fe;
|
|
|
+
|
|
|
+ mlog_entry("blkno: %llu\n", blkno);
|
|
|
+
|
|
|
+ /* dirty read disk */
|
|
|
+ status = ocfs2_read_blocks_sync(osb, blkno, 1, &inode_bh);
|
|
|
+ if (status < 0) {
|
|
|
+ mlog(ML_ERROR, "read block %llu failed %d\n", blkno, status);
|
|
|
+ goto bail;
|
|
|
+ }
|
|
|
+
|
|
|
+ inode_fe = (struct ocfs2_dinode *) inode_bh->b_data;
|
|
|
+ if (!OCFS2_IS_VALID_DINODE(inode_fe)) {
|
|
|
+ mlog(ML_ERROR, "invalid inode %llu requested\n", blkno);
|
|
|
+ status = -EINVAL;
|
|
|
+ goto bail;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (le16_to_cpu(inode_fe->i_suballoc_slot) != OCFS2_INVALID_SLOT &&
|
|
|
+ (u32)le16_to_cpu(inode_fe->i_suballoc_slot) > osb->max_slots - 1) {
|
|
|
+ mlog(ML_ERROR, "inode %llu has invalid suballoc slot %u\n",
|
|
|
+ blkno, (u32)le16_to_cpu(inode_fe->i_suballoc_slot));
|
|
|
+ status = -EINVAL;
|
|
|
+ goto bail;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (suballoc_slot)
|
|
|
+ *suballoc_slot = le16_to_cpu(inode_fe->i_suballoc_slot);
|
|
|
+ if (suballoc_bit)
|
|
|
+ *suballoc_bit = le16_to_cpu(inode_fe->i_suballoc_bit);
|
|
|
+
|
|
|
+bail:
|
|
|
+ brelse(inode_bh);
|
|
|
+
|
|
|
+ mlog_exit(status);
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * test whether bit is SET in allocator bitmap or not. on success, 0
|
|
|
+ * is returned and *res is 1 for SET; 0 otherwise. when fails, errno
|
|
|
+ * is returned and *res is meaningless. Call this after you have
|
|
|
+ * cluster locked against suballoc, or you may get a result based on
|
|
|
+ * non-up2date contents
|
|
|
+ */
|
|
|
+static int ocfs2_test_suballoc_bit(struct ocfs2_super *osb,
|
|
|
+ struct inode *suballoc,
|
|
|
+ struct buffer_head *alloc_bh, u64 blkno,
|
|
|
+ u16 bit, int *res)
|
|
|
+{
|
|
|
+ struct ocfs2_dinode *alloc_fe;
|
|
|
+ struct ocfs2_group_desc *group;
|
|
|
+ struct buffer_head *group_bh = NULL;
|
|
|
+ u64 bg_blkno;
|
|
|
+ int status;
|
|
|
+
|
|
|
+ mlog_entry("blkno: %llu bit: %u\n", blkno, (unsigned int)bit);
|
|
|
+
|
|
|
+ alloc_fe = (struct ocfs2_dinode *)alloc_bh->b_data;
|
|
|
+ if ((bit + 1) > ocfs2_bits_per_group(&alloc_fe->id2.i_chain)) {
|
|
|
+ mlog(ML_ERROR, "suballoc bit %u out of range of %u\n",
|
|
|
+ (unsigned int)bit,
|
|
|
+ ocfs2_bits_per_group(&alloc_fe->id2.i_chain));
|
|
|
+ status = -EINVAL;
|
|
|
+ goto bail;
|
|
|
+ }
|
|
|
+
|
|
|
+ bg_blkno = ocfs2_which_suballoc_group(blkno, bit);
|
|
|
+ status = ocfs2_read_group_descriptor(suballoc, alloc_fe, bg_blkno,
|
|
|
+ &group_bh);
|
|
|
+ if (status < 0) {
|
|
|
+ mlog(ML_ERROR, "read group %llu failed %d\n", bg_blkno, status);
|
|
|
+ goto bail;
|
|
|
+ }
|
|
|
+
|
|
|
+ group = (struct ocfs2_group_desc *) group_bh->b_data;
|
|
|
+ *res = ocfs2_test_bit(bit, (unsigned long *)group->bg_bitmap);
|
|
|
+
|
|
|
+bail:
|
|
|
+ brelse(group_bh);
|
|
|
+
|
|
|
+ mlog_exit(status);
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Test if the bit representing this inode (blkno) is set in the
|
|
|
+ * suballocator.
|
|
|
+ *
|
|
|
+ * On success, 0 is returned and *res is 1 for SET; 0 otherwise.
|
|
|
+ *
|
|
|
+ * In the event of failure, a negative value is returned and *res is
|
|
|
+ * meaningless.
|
|
|
+ *
|
|
|
+ * Callers must make sure to hold nfs_sync_lock to prevent
|
|
|
+ * ocfs2_delete_inode() on another node from accessing the same
|
|
|
+ * suballocator concurrently.
|
|
|
+ */
|
|
|
+int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res)
|
|
|
+{
|
|
|
+ int status;
|
|
|
+ u16 suballoc_bit = 0, suballoc_slot = 0;
|
|
|
+ struct inode *inode_alloc_inode;
|
|
|
+ struct buffer_head *alloc_bh = NULL;
|
|
|
+
|
|
|
+ mlog_entry("blkno: %llu", blkno);
|
|
|
+
|
|
|
+ status = ocfs2_get_suballoc_slot_bit(osb, blkno, &suballoc_slot,
|
|
|
+ &suballoc_bit);
|
|
|
+ if (status < 0) {
|
|
|
+ mlog(ML_ERROR, "get alloc slot and bit failed %d\n", status);
|
|
|
+ goto bail;
|
|
|
+ }
|
|
|
+
|
|
|
+ inode_alloc_inode =
|
|
|
+ ocfs2_get_system_file_inode(osb, INODE_ALLOC_SYSTEM_INODE,
|
|
|
+ suballoc_slot);
|
|
|
+ if (!inode_alloc_inode) {
|
|
|
+ /* the error code could be inaccurate, but we are not able to
|
|
|
+ * get the correct one. */
|
|
|
+ status = -EINVAL;
|
|
|
+ mlog(ML_ERROR, "unable to get alloc inode in slot %u\n",
|
|
|
+ (u32)suballoc_slot);
|
|
|
+ goto bail;
|
|
|
+ }
|
|
|
+
|
|
|
+ mutex_lock(&inode_alloc_inode->i_mutex);
|
|
|
+ status = ocfs2_inode_lock(inode_alloc_inode, &alloc_bh, 0);
|
|
|
+ if (status < 0) {
|
|
|
+ mutex_unlock(&inode_alloc_inode->i_mutex);
|
|
|
+ mlog(ML_ERROR, "lock on alloc inode on slot %u failed %d\n",
|
|
|
+ (u32)suballoc_slot, status);
|
|
|
+ goto bail;
|
|
|
+ }
|
|
|
+
|
|
|
+ status = ocfs2_test_suballoc_bit(osb, inode_alloc_inode, alloc_bh,
|
|
|
+ blkno, suballoc_bit, res);
|
|
|
+ if (status < 0)
|
|
|
+ mlog(ML_ERROR, "test suballoc bit failed %d\n", status);
|
|
|
+
|
|
|
+ ocfs2_inode_unlock(inode_alloc_inode, 0);
|
|
|
+ mutex_unlock(&inode_alloc_inode->i_mutex);
|
|
|
+
|
|
|
+ iput(inode_alloc_inode);
|
|
|
+ brelse(alloc_bh);
|
|
|
+bail:
|
|
|
+ mlog_exit(status);
|
|
|
+ return status;
|
|
|
+}
|