📄 xfs_vnodeops.c
字号:
*tpp = tp; return 0;}intxfs_release( xfs_inode_t *ip){ bhv_vnode_t *vp = XFS_ITOV(ip); xfs_mount_t *mp = ip->i_mount; int error; if (!VN_ISREG(vp) || (ip->i_d.di_mode == 0)) return 0; /* If this is a read-only mount, don't do this (would generate I/O) */ if (mp->m_flags & XFS_MOUNT_RDONLY) return 0; if (!XFS_FORCED_SHUTDOWN(mp)) { int truncated; /* * If we are using filestreams, and we have an unlinked * file that we are processing the last close on, then nothing * will be able to reopen and write to this file. Purge this * inode from the filestreams cache so that it doesn't delay * teardown of the inode. */ if ((ip->i_d.di_nlink == 0) && xfs_inode_is_filestream(ip)) xfs_filestream_deassociate(ip); /* * If we previously truncated this file and removed old data * in the process, we want to initiate "early" writeout on * the last close. This is an attempt to combat the notorious * NULL files problem which is particularly noticable from a * truncate down, buffered (re-)write (delalloc), followed by * a crash. What we are effectively doing here is * significantly reducing the time window where we'd otherwise * be exposed to that problem. */ truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED); if (truncated && VN_DIRTY(vp) && ip->i_delayed_blks > 0) xfs_flush_pages(ip, 0, -1, XFS_B_ASYNC, FI_NONE); }#ifdef HAVE_REFCACHE /* If we are in the NFS reference cache then don't do this now */ if (ip->i_refcache) return 0;#endif if (ip->i_d.di_nlink != 0) { if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && ((ip->i_size > 0) || (VN_CACHED(vp) > 0 || ip->i_delayed_blks > 0)) && (ip->i_df.if_flags & XFS_IFEXTENTS)) && (!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) { error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK); if (error) return error; /* Update linux inode block count after free above */ vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks); } } return 0;}/* * xfs_inactive * * This is called when the vnode reference count for the vnode * goes to zero. If the file has been unlinked, then it must * now be truncated. Also, we clear all of the read-ahead state * kept for the inode here since the file is now closed. */intxfs_inactive( xfs_inode_t *ip){ bhv_vnode_t *vp = XFS_ITOV(ip); xfs_bmap_free_t free_list; xfs_fsblock_t first_block; int committed; xfs_trans_t *tp; xfs_mount_t *mp; int error; int truncate; vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); /* * If the inode is already free, then there can be nothing * to clean up here. */ if (ip->i_d.di_mode == 0 || VN_BAD(vp)) { ASSERT(ip->i_df.if_real_bytes == 0); ASSERT(ip->i_df.if_broot_bytes == 0); return VN_INACTIVE_CACHE; } /* * Only do a truncate if it's a regular file with * some actual space in it. It's OK to look at the * inode's fields without the lock because we're the * only one with a reference to the inode. */ truncate = ((ip->i_d.di_nlink == 0) && ((ip->i_d.di_size != 0) || (ip->i_size != 0) || (ip->i_d.di_nextents > 0) || (ip->i_delayed_blks > 0)) && ((ip->i_d.di_mode & S_IFMT) == S_IFREG)); mp = ip->i_mount; if (ip->i_d.di_nlink == 0 && DM_EVENT_ENABLED(ip, DM_EVENT_DESTROY)) { (void) XFS_SEND_DESTROY(mp, vp, DM_RIGHT_NULL); } error = 0; /* If this is a read-only mount, don't do this (would generate I/O) */ if (mp->m_flags & XFS_MOUNT_RDONLY) goto out; if (ip->i_d.di_nlink != 0) { if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && ((ip->i_size > 0) || (VN_CACHED(vp) > 0 || ip->i_delayed_blks > 0)) && (ip->i_df.if_flags & XFS_IFEXTENTS) && (!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) || (ip->i_delayed_blks != 0)))) { error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK); if (error) return VN_INACTIVE_CACHE; /* Update linux inode block count after free above */ vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks); } goto out; } ASSERT(ip->i_d.di_nlink == 0); if ((error = XFS_QM_DQATTACH(mp, ip, 0))) return VN_INACTIVE_CACHE; tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); if (truncate) { /* * Do the xfs_itruncate_start() call before * reserving any log space because itruncate_start * will call into the buffer cache and we can't * do that within a transaction. */ xfs_ilock(ip, XFS_IOLOCK_EXCL); error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0); if (error) { xfs_trans_cancel(tp, 0); xfs_iunlock(ip, XFS_IOLOCK_EXCL); return VN_INACTIVE_CACHE; } error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT); if (error) { /* Don't call itruncate_cleanup */ ASSERT(XFS_FORCED_SHUTDOWN(mp)); xfs_trans_cancel(tp, 0); xfs_iunlock(ip, XFS_IOLOCK_EXCL); return VN_INACTIVE_CACHE; } xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); xfs_trans_ihold(tp, ip); /* * normally, we have to run xfs_itruncate_finish sync. * But if filesystem is wsync and we're in the inactive * path, then we know that nlink == 0, and that the * xaction that made nlink == 0 is permanently committed * since xfs_remove runs as a synchronous transaction. */ error = xfs_itruncate_finish(&tp, ip, 0, XFS_DATA_FORK, (!(mp->m_flags & XFS_MOUNT_WSYNC) ? 1 : 0)); if (error) { xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); return VN_INACTIVE_CACHE; } } else if ((ip->i_d.di_mode & S_IFMT) == S_IFLNK) { /* * If we get an error while cleaning up a * symlink we bail out. */ error = (ip->i_d.di_size > XFS_IFORK_DSIZE(ip)) ? xfs_inactive_symlink_rmt(ip, &tp) : xfs_inactive_symlink_local(ip, &tp); if (error) { ASSERT(tp == NULL); return VN_INACTIVE_CACHE; } xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); xfs_trans_ihold(tp, ip); } else { error = xfs_trans_reserve(tp, 0, XFS_IFREE_LOG_RES(mp), 0, XFS_TRANS_PERM_LOG_RES, XFS_INACTIVE_LOG_COUNT); if (error) { ASSERT(XFS_FORCED_SHUTDOWN(mp)); xfs_trans_cancel(tp, 0); return VN_INACTIVE_CACHE; } xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); xfs_trans_ihold(tp, ip); } /* * If there are attributes associated with the file * then blow them away now. The code calls a routine * that recursively deconstructs the attribute fork. * We need to just commit the current transaction * because we can't use it for xfs_attr_inactive(). */ if (ip->i_d.di_anextents > 0) { error = xfs_inactive_attrs(ip, &tp); /* * If we got an error, the transaction is already * cancelled, and the inode is unlocked. Just get out. */ if (error) return VN_INACTIVE_CACHE; } else if (ip->i_afp) { xfs_idestroy_fork(ip, XFS_ATTR_FORK); } /* * Free the inode. */ XFS_BMAP_INIT(&free_list, &first_block); error = xfs_ifree(tp, ip, &free_list); if (error) { /* * If we fail to free the inode, shut down. The cancel * might do that, we need to make sure. Otherwise the * inode might be lost for a long time or forever. */ if (!XFS_FORCED_SHUTDOWN(mp)) { cmn_err(CE_NOTE, "xfs_inactive: xfs_ifree() returned an error = %d on %s", error, mp->m_fsname); xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR); } xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); } else { /* * Credit the quota account(s). The inode is gone. */ XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_ICOUNT, -1); /* * Just ignore errors at this point. There is * nothing we can do except to try to keep going. */ (void) xfs_bmap_finish(&tp, &free_list, &committed); (void) xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); } /* * Release the dquots held by inode, if any. */ XFS_QM_DQDETACH(mp, ip); xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); out: return VN_INACTIVE_CACHE;}intxfs_lookup( xfs_inode_t *dp, bhv_vname_t *dentry, bhv_vnode_t **vpp){ xfs_inode_t *ip; xfs_ino_t e_inum; int error; uint lock_mode; vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return XFS_ERROR(EIO); lock_mode = xfs_ilock_map_shared(dp); error = xfs_dir_lookup_int(dp, lock_mode, dentry, &e_inum, &ip); if (!error) { *vpp = XFS_ITOV(ip); ITRACE(ip); } xfs_iunlock_map_shared(dp, lock_mode); return error;}intxfs_create( xfs_inode_t *dp, bhv_vname_t *dentry, mode_t mode, xfs_dev_t rdev, bhv_vnode_t **vpp, cred_t *credp){ char *name = VNAME(dentry); xfs_mount_t *mp = dp->i_mount; bhv_vnode_t *dir_vp = XFS_ITOV(dp); xfs_inode_t *ip; bhv_vnode_t *vp = NULL; xfs_trans_t *tp; int error; xfs_bmap_free_t free_list; xfs_fsblock_t first_block; boolean_t unlock_dp_on_error = B_FALSE; int dm_event_sent = 0; uint cancel_flags; int committed; xfs_prid_t prid; struct xfs_dquot *udqp, *gdqp; uint resblks; int namelen; ASSERT(!*vpp); vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); namelen = VNAMELEN(dentry); if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) { error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE, dir_vp, DM_RIGHT_NULL, NULL, DM_RIGHT_NULL, name, NULL, mode, 0, 0); if (error) return error; dm_event_sent = 1; } if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); /* Return through std_return after this point. */ udqp = gdqp = NULL; if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) prid = dp->i_d.di_projid; else prid = (xfs_prid_t)dfltprid; /* * Make sure that we have allocated dquot(s) on disk. */ error = XFS_QM_DQVOPALLOC(mp, dp, current_fsuid(credp), current_fsgid(credp), prid, XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp); if (error) goto std_return; ip = NULL; tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE); cancel_flags = XFS_TRANS_RELEASE_LOG_RES; resblks = XFS_CREATE_SPACE_RES(mp, namelen); /* * Initially assume that the file does not exist and * reserve the resources for that case. If that is not * the case we'll drop the one we have and get a more * appropriate transaction later. */ error = xfs_trans_reserve(tp, resblks, XFS_CREATE_LOG_RES(mp), 0, XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT); if (error == ENOSPC) { resblks = 0; error = xfs_trans_reserve(tp, 0, XFS_CREATE_LOG_RES(mp), 0, XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT); } if (error) { cancel_flags = 0; goto error_return; } xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); unlock_dp_on_error = B_TRUE; XFS_BMAP_INIT(&free_list, &first_block); ASSERT(ip == NULL); /* * Reserve disk quota and the inode. */ error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0); if (error) goto error_return; if (resblks == 0 && (error = xfs_dir_canenter(tp, dp, name, namelen))) goto error_return; error = xfs_dir_ialloc(&tp, dp, mode, 1, rdev, credp, prid, resblks > 0, &ip, &committed); if (error) { if (error == ENOSPC) goto error_return; goto abort_return; } ITRACE(ip); /* * At this point, we've gotten a newly allocated inode. * It is locked (and joined to the transaction). */ ASSERT(ismrlocked (&ip->i_lock, MR_UPDATE)); /* * Now we join the directory inode to the transaction. We do not do it * earlier because xfs_dir_ialloc might commit the previous transaction * (and release all the locks). An error from here on will result in * the transaction cancel unlocking dp so don't do it explicitly in the * error path. */ VN_HOLD(dir_vp); xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); unlock_dp_on_error = B_FALSE; error = xfs_dir_createname(tp, dp, name, namelen, ip->i_ino, &first_block, &free_list, resblks ? resblks - XFS_IALLOC_SPACE_RES(mp) : 0); if (error) { ASSERT(error != ENOSPC); goto abort_return; } xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); /* * If this is a synchronous mount, make sure that the * create transaction goes to disk before returning to * the user. */ if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { xfs_trans_set_sync(tp); } dp->i_gen++; /* * Attach the dquot(s) to the inodes and modify them incore. * These ids of the inode couldn't have changed since the new * inode has been locked ever since it was created. */ XFS_QM_DQVOPCREATE(mp, tp, ip, udqp, gdqp); /* * xfs_trans_commit normally decrements the vnode ref count * when it unlocks the inode. Since we want to return the * vnode to the caller, we bump the vnode ref count now. */ IHOLD(ip); vp = XFS_ITOV(ip); error = xfs_bmap_finish(&tp, &free_list, &committed); if (error) { xfs_bmap_cancel(&free_list); goto abort_rele; } error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); if (error) { IRELE(ip); tp = NULL; goto error_return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -