📄 xfs_rename.c
字号:
/* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */#include "xfs.h"#include "xfs_fs.h"#include "xfs_types.h"#include "xfs_log.h"#include "xfs_inum.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir2.h"#include "xfs_dmapi.h"#include "xfs_mount.h"#include "xfs_da_btree.h"#include "xfs_bmap_btree.h"#include "xfs_dir2_sf.h"#include "xfs_attr_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_inode_item.h"#include "xfs_bmap.h"#include "xfs_error.h"#include "xfs_quota.h"#include "xfs_refcache.h"#include "xfs_utils.h"#include "xfs_trans_space.h"/* * Given an array of up to 4 inode pointers, unlock the pointed to inodes. * If there are fewer than 4 entries in the array, the empty entries will * be at the end and will have NULL pointers in them. */STATIC voidxfs_rename_unlock4( xfs_inode_t **i_tab, uint lock_mode){ int i; xfs_iunlock(i_tab[0], lock_mode); for (i = 1; i < 4; i++) { if (i_tab[i] == NULL) { break; } /* * Watch out for duplicate entries in the table. */ if (i_tab[i] != i_tab[i-1]) { xfs_iunlock(i_tab[i], lock_mode); } }}#ifdef DEBUGint xfs_rename_skip, xfs_rename_nskip;#endif/* * The following routine will acquire the locks required for a rename * operation. The code understands the semantics of renames and will * validate that name1 exists under dp1 & that name2 may or may not * exist under dp2. * * We are renaming dp1/name1 to dp2/name2. * * Return ENOENT if dp1 does not exist, other lookup errors, or 0 for success. */STATIC intxfs_lock_for_rename( xfs_inode_t *dp1, /* old (source) directory inode */ xfs_inode_t *dp2, /* new (target) directory inode */ bhv_vname_t *vname1,/* old entry name */ bhv_vname_t *vname2,/* new entry name */ xfs_inode_t **ipp1, /* inode of old entry */ xfs_inode_t **ipp2, /* inode of new entry, if it already exists, NULL otherwise. */ xfs_inode_t **i_tab,/* array of inode returned, sorted */ int *num_inodes) /* number of inodes in array */{ xfs_inode_t *ip1, *ip2, *temp; xfs_ino_t inum1, inum2; int error; int i, j; uint lock_mode; int diff_dirs = (dp1 != dp2); ip2 = NULL; /* * First, find out the current inums of the entries so that we * can determine the initial locking order. We'll have to * sanity check stuff after all the locks have been acquired * to see if we still have the right inodes, directories, etc. */ lock_mode = xfs_ilock_map_shared(dp1); error = xfs_get_dir_entry(vname1, &ip1); if (error) { xfs_iunlock_map_shared(dp1, lock_mode); return error; } inum1 = ip1->i_ino; ASSERT(ip1); ITRACE(ip1); /* * Unlock dp1 and lock dp2 if they are different. */ if (diff_dirs) { xfs_iunlock_map_shared(dp1, lock_mode); lock_mode = xfs_ilock_map_shared(dp2); } error = xfs_dir_lookup_int(dp2, lock_mode, vname2, &inum2, &ip2); if (error == ENOENT) { /* target does not need to exist. */ inum2 = 0; } else if (error) { /* * If dp2 and dp1 are the same, the next line unlocks dp1. * Got it? */ xfs_iunlock_map_shared(dp2, lock_mode); IRELE (ip1); return error; } else { ITRACE(ip2); } /* * i_tab contains a list of pointers to inodes. We initialize * the table here & we'll sort it. We will then use it to * order the acquisition of the inode locks. * * Note that the table may contain duplicates. e.g., dp1 == dp2. */ i_tab[0] = dp1; i_tab[1] = dp2; i_tab[2] = ip1; if (inum2 == 0) { *num_inodes = 3; i_tab[3] = NULL; } else { *num_inodes = 4; i_tab[3] = ip2; } /* * Sort the elements via bubble sort. (Remember, there are at * most 4 elements to sort, so this is adequate.) */ for (i=0; i < *num_inodes; i++) { for (j=1; j < *num_inodes; j++) { if (i_tab[j]->i_ino < i_tab[j-1]->i_ino) { temp = i_tab[j]; i_tab[j] = i_tab[j-1]; i_tab[j-1] = temp; } } } /* * We have dp2 locked. If it isn't first, unlock it. * If it is first, tell xfs_lock_inodes so it can skip it * when locking. if dp1 == dp2, xfs_lock_inodes will skip both * since they are equal. xfs_lock_inodes needs all these inodes * so that it can unlock and retry if there might be a dead-lock * potential with the log. */ if (i_tab[0] == dp2 && lock_mode == XFS_ILOCK_SHARED) {#ifdef DEBUG xfs_rename_skip++;#endif xfs_lock_inodes(i_tab, *num_inodes, 1, XFS_ILOCK_SHARED); } else {#ifdef DEBUG xfs_rename_nskip++;#endif xfs_iunlock_map_shared(dp2, lock_mode); xfs_lock_inodes(i_tab, *num_inodes, 0, XFS_ILOCK_SHARED); } /* * Set the return value. Null out any unused entries in i_tab. */ *ipp1 = *ipp2 = NULL; for (i=0; i < *num_inodes; i++) { if (i_tab[i]->i_ino == inum1) { *ipp1 = i_tab[i]; } if (i_tab[i]->i_ino == inum2) { *ipp2 = i_tab[i]; } } for (;i < 4; i++) { i_tab[i] = NULL; } return 0;}/* * xfs_rename */intxfs_rename( xfs_inode_t *src_dp, bhv_vname_t *src_vname, bhv_vnode_t *target_dir_vp, bhv_vname_t *target_vname){ bhv_vnode_t *src_dir_vp = XFS_ITOV(src_dp); xfs_trans_t *tp; xfs_inode_t *target_dp, *src_ip, *target_ip; xfs_mount_t *mp = src_dp->i_mount; int new_parent; /* moving to a new dir */ int src_is_directory; /* src_name is a directory */ int error; xfs_bmap_free_t free_list; xfs_fsblock_t first_block; int cancel_flags; int committed; xfs_inode_t *inodes[4]; int target_ip_dropped = 0; /* dropped target_ip link? */ int spaceres; int target_link_zero = 0; int num_inodes; char *src_name = VNAME(src_vname); char *target_name = VNAME(target_vname); int src_namelen = VNAMELEN(src_vname); int target_namelen = VNAMELEN(target_vname); vn_trace_entry(src_dp, "xfs_rename", (inst_t *)__return_address); vn_trace_entry(xfs_vtoi(target_dir_vp), "xfs_rename", (inst_t *)__return_address); /* * Find the XFS behavior descriptor for the target directory * vnode since it was not handed to us. */ target_dp = xfs_vtoi(target_dir_vp); if (target_dp == NULL) { return XFS_ERROR(EXDEV); } if (DM_EVENT_ENABLED(src_dp, DM_EVENT_RENAME) || DM_EVENT_ENABLED(target_dp, DM_EVENT_RENAME)) { error = XFS_SEND_NAMESP(mp, DM_EVENT_RENAME, src_dir_vp, DM_RIGHT_NULL, target_dir_vp, DM_RIGHT_NULL, src_name, target_name, 0, 0, 0); if (error) { return error; } } /* Return through std_return after this point. */ /* * Lock all the participating inodes. Depending upon whether * the target_name exists in the target directory, and * whether the target directory is the same as the source * directory, we can lock from 2 to 4 inodes. * xfs_lock_for_rename() will return ENOENT if src_name * does not exist in the source directory. */ tp = NULL; error = xfs_lock_for_rename(src_dp, target_dp, src_vname, target_vname, &src_ip, &target_ip, inodes, &num_inodes); if (error) { /* * We have nothing locked, no inode references, and * no transaction, so just get out. */ goto std_return; } ASSERT(src_ip != NULL); if ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR) { /* * Check for link count overflow on target_dp */ if (target_ip == NULL && (src_dp != target_dp) && target_dp->i_d.di_nlink >= XFS_MAXLINK) { error = XFS_ERROR(EMLINK); xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED); goto rele_return; } } /* * If we are using project inheritance, we only allow renames
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -