📄 inode.c
字号:
if (sysfile) OCFS2_I(inode)->ip_flags |= OCFS2_INODE_SYSTEM_FILE; status = 0;bail: if (args && bh) brelse(bh); mlog_exit(status); return status;}void ocfs2_sync_blockdev(struct super_block *sb){ sync_blockdev(sb->s_bdev);}static int ocfs2_truncate_for_delete(struct ocfs2_super *osb, struct inode *inode, struct buffer_head *fe_bh){ int status = 0; struct ocfs2_journal_handle *handle = NULL; struct ocfs2_truncate_context *tc = NULL; struct ocfs2_dinode *fe; mlog_entry_void(); fe = (struct ocfs2_dinode *) fe_bh->b_data; /* zero allocation, zero truncate :) */ if (!fe->i_clusters) goto bail; handle = ocfs2_start_trans(osb, handle, OCFS2_INODE_UPDATE_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); handle = NULL; mlog_errno(status); goto bail; } status = ocfs2_set_inode_size(handle, inode, fe_bh, 0ULL); if (status < 0) { mlog_errno(status); goto bail; } ocfs2_commit_trans(handle); handle = NULL; status = ocfs2_prepare_truncate(osb, inode, fe_bh, &tc); if (status < 0) { mlog_errno(status); goto bail; } status = ocfs2_commit_truncate(osb, inode, fe_bh, tc); if (status < 0) { mlog_errno(status); goto bail; }bail: if (handle) ocfs2_commit_trans(handle); mlog_exit(status); return status;}static int ocfs2_remove_inode(struct inode *inode, struct buffer_head *di_bh, struct inode *orphan_dir_inode, struct buffer_head *orphan_dir_bh){ int status; struct inode *inode_alloc_inode = NULL; struct buffer_head *inode_alloc_bh = NULL; struct ocfs2_journal_handle *handle; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct ocfs2_dinode *di = (struct ocfs2_dinode *) di_bh->b_data; inode_alloc_inode = ocfs2_get_system_file_inode(osb, INODE_ALLOC_SYSTEM_INODE, le16_to_cpu(di->i_suballoc_slot)); if (!inode_alloc_inode) { status = -EEXIST; mlog_errno(status); goto bail; } mutex_lock(&inode_alloc_inode->i_mutex); status = ocfs2_meta_lock(inode_alloc_inode, NULL, &inode_alloc_bh, 1); if (status < 0) { mutex_unlock(&inode_alloc_inode->i_mutex); mlog_errno(status); goto bail; } handle = ocfs2_start_trans(osb, NULL, OCFS2_DELETE_INODE_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); mlog_errno(status); goto bail_unlock; } status = ocfs2_orphan_del(osb, handle, orphan_dir_inode, inode, orphan_dir_bh); if (status < 0) { mlog_errno(status); goto bail_commit; } /* set the inodes dtime */ status = ocfs2_journal_access(handle, inode, di_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto bail_commit; } di->i_dtime = cpu_to_le64(CURRENT_TIME.tv_sec); le32_and_cpu(&di->i_flags, ~(OCFS2_VALID_FL | OCFS2_ORPHANED_FL)); status = ocfs2_journal_dirty(handle, di_bh); if (status < 0) { mlog_errno(status); goto bail_commit; } ocfs2_remove_from_cache(inode, di_bh); status = ocfs2_free_dinode(handle, inode_alloc_inode, inode_alloc_bh, di); if (status < 0) mlog_errno(status);bail_commit: ocfs2_commit_trans(handle);bail_unlock: ocfs2_meta_unlock(inode_alloc_inode, 1); mutex_unlock(&inode_alloc_inode->i_mutex); brelse(inode_alloc_bh);bail: iput(inode_alloc_inode); return status;}/* * Serialize with orphan dir recovery. If the process doing * recovery on this orphan dir does an iget() with the dir * i_mutex held, we'll deadlock here. Instead we detect this * and exit early - recovery will wipe this inode for us. */static int ocfs2_check_orphan_recovery_state(struct ocfs2_super *osb, int slot){ int ret = 0; spin_lock(&osb->osb_lock); if (ocfs2_node_map_test_bit(osb, &osb->osb_recovering_orphan_dirs, slot)) { mlog(0, "Recovery is happening on orphan dir %d, will skip " "this inode\n", slot); ret = -EDEADLK; goto out; } /* This signals to the orphan recovery process that is should * wait for us to handle the wipe. */ osb->osb_orphan_wipes[slot]++;out: spin_unlock(&osb->osb_lock); return ret;}static void ocfs2_signal_wipe_completion(struct ocfs2_super *osb, int slot){ spin_lock(&osb->osb_lock); osb->osb_orphan_wipes[slot]--; spin_unlock(&osb->osb_lock); wake_up(&osb->osb_wipe_event);}static int ocfs2_wipe_inode(struct inode *inode, struct buffer_head *di_bh){ int status, orphaned_slot; struct inode *orphan_dir_inode = NULL; struct buffer_head *orphan_dir_bh = NULL; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); /* We've already voted on this so it should be readonly - no * spinlock needed. */ orphaned_slot = OCFS2_I(inode)->ip_orphaned_slot; status = ocfs2_check_orphan_recovery_state(osb, orphaned_slot); if (status) return status; orphan_dir_inode = ocfs2_get_system_file_inode(osb, ORPHAN_DIR_SYSTEM_INODE, orphaned_slot); if (!orphan_dir_inode) { status = -EEXIST; mlog_errno(status); goto bail; } /* Lock the orphan dir. The lock will be held for the entire * delete_inode operation. We do this now to avoid races with * recovery completion on other nodes. */ mutex_lock(&orphan_dir_inode->i_mutex); status = ocfs2_meta_lock(orphan_dir_inode, NULL, &orphan_dir_bh, 1); if (status < 0) { mutex_unlock(&orphan_dir_inode->i_mutex); mlog_errno(status); goto bail; } /* we do this while holding the orphan dir lock because we * don't want recovery being run from another node to vote for * an inode delete on us -- this will result in two nodes * truncating the same file! */ status = ocfs2_truncate_for_delete(osb, inode, di_bh); if (status < 0) { mlog_errno(status); goto bail_unlock_dir; } status = ocfs2_remove_inode(inode, di_bh, orphan_dir_inode, orphan_dir_bh); if (status < 0) mlog_errno(status);bail_unlock_dir: ocfs2_meta_unlock(orphan_dir_inode, 1); mutex_unlock(&orphan_dir_inode->i_mutex); brelse(orphan_dir_bh);bail: iput(orphan_dir_inode); ocfs2_signal_wipe_completion(osb, orphaned_slot); 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 %"MLFu64".\n", 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;}/* Query the cluster to determine whether we should wipe an inode from * disk or not. * * Requires the inode to have the cluster lock. */static int ocfs2_query_inode_wipe(struct inode *inode, struct buffer_head *di_bh, int *wipe){ int status = 0; struct ocfs2_inode_info *oi = OCFS2_I(inode); struct ocfs2_dinode *di; *wipe = 0; /* While we were waiting for the cluster lock in * ocfs2_delete_inode, another node might have asked to delete * the inode. Recheck our flags to catch this. */ if (!ocfs2_inode_is_valid_to_delete(inode)) { mlog(0, "Skipping delete of %"MLFu64" because flags changed\n", oi->ip_blkno); goto bail; } /* Now that we have an up to date inode, we can double check * the link count. */ if (inode->i_nlink) { mlog(0, "Skipping delete of %"MLFu64" because nlink = %u\n", oi->ip_blkno, inode->i_nlink); goto bail; } /* Do some basic inode verification... */ di = (struct ocfs2_dinode *) di_bh->b_data; if (!(di->i_flags & cpu_to_le32(OCFS2_ORPHANED_FL))) { /* for lack of a better error? */ status = -EEXIST; mlog(ML_ERROR, "Inode %"MLFu64" (on-disk %"MLFu64") not orphaned! " "Disk flags 0x%x, inode flags 0x%x\n", oi->ip_blkno, di->i_blkno, di->i_flags, oi->ip_flags); goto bail; } /* has someone already deleted us?! baaad... */ if (di->i_dtime) { status = -EEXIST; mlog_errno(status); goto bail; } status = ocfs2_request_delete_vote(inode); /* -EBUSY means that other nodes are still using the * inode. We're done here though, so avoid doing anything on * disk and let them worry about deleting it. */ if (status == -EBUSY) { status = 0; mlog(0, "Skipping delete of %"MLFu64" because it is in use on" "other nodes\n", oi->ip_blkno); goto bail; } if (status < 0) { mlog_errno(status); goto bail; } spin_lock(&oi->ip_lock); if (oi->ip_orphaned_slot == OCFS2_INVALID_SLOT) { /* Nobody knew which slot this inode was orphaned * into. This may happen during node death and * recovery knows how to clean it up so we can safely * ignore this inode for now on. */ mlog(0, "Nobody knew where inode %"MLFu64" was orphaned!\n", oi->ip_blkno); } else { *wipe = 1; mlog(0, "Inode %"MLFu64" is ok to wipe from orphan dir %d\n", oi->ip_blkno, oi->ip_orphaned_slot); } spin_unlock(&oi->ip_lock);bail: return status;}/* Support function for ocfs2_delete_inode. Will help us keep the * inode data in a consistent state for clear_inode. Always truncates * pages, optionally sync's them first. */static void ocfs2_cleanup_delete_inode(struct inode *inode, int sync_data){ mlog(0, "Cleanup inode %"MLFu64", sync = %d\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -