aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_vnodeops.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_vnodeops.c')
-rw-r--r--fs/xfs/xfs_vnodeops.c324
1 files changed, 84 insertions, 240 deletions
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index d76565bfcb7b..8297a8c5af90 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -2116,13 +2116,6 @@ again:
2116#endif 2116#endif
2117} 2117}
2118 2118
2119#ifdef DEBUG
2120#define REMOVE_DEBUG_TRACE(x) {remove_which_error_return = (x);}
2121int remove_which_error_return = 0;
2122#else /* ! DEBUG */
2123#define REMOVE_DEBUG_TRACE(x)
2124#endif /* ! DEBUG */
2125
2126int 2119int
2127xfs_remove( 2120xfs_remove(
2128 xfs_inode_t *dp, 2121 xfs_inode_t *dp,
@@ -2131,6 +2124,7 @@ xfs_remove(
2131{ 2124{
2132 xfs_mount_t *mp = dp->i_mount; 2125 xfs_mount_t *mp = dp->i_mount;
2133 xfs_trans_t *tp = NULL; 2126 xfs_trans_t *tp = NULL;
2127 int is_dir = S_ISDIR(ip->i_d.di_mode);
2134 int error = 0; 2128 int error = 0;
2135 xfs_bmap_free_t free_list; 2129 xfs_bmap_free_t free_list;
2136 xfs_fsblock_t first_block; 2130 xfs_fsblock_t first_block;
@@ -2138,8 +2132,10 @@ xfs_remove(
2138 int committed; 2132 int committed;
2139 int link_zero; 2133 int link_zero;
2140 uint resblks; 2134 uint resblks;
2135 uint log_count;
2141 2136
2142 xfs_itrace_entry(dp); 2137 xfs_itrace_entry(dp);
2138 xfs_itrace_entry(ip);
2143 2139
2144 if (XFS_FORCED_SHUTDOWN(mp)) 2140 if (XFS_FORCED_SHUTDOWN(mp))
2145 return XFS_ERROR(EIO); 2141 return XFS_ERROR(EIO);
@@ -2152,19 +2148,23 @@ xfs_remove(
2152 return error; 2148 return error;
2153 } 2149 }
2154 2150
2155 xfs_itrace_entry(ip);
2156 xfs_itrace_ref(ip);
2157
2158 error = XFS_QM_DQATTACH(mp, dp, 0); 2151 error = XFS_QM_DQATTACH(mp, dp, 0);
2159 if (!error) 2152 if (error)
2160 error = XFS_QM_DQATTACH(mp, ip, 0); 2153 goto std_return;
2161 if (error) { 2154
2162 REMOVE_DEBUG_TRACE(__LINE__); 2155 error = XFS_QM_DQATTACH(mp, ip, 0);
2156 if (error)
2163 goto std_return; 2157 goto std_return;
2164 }
2165 2158
2166 tp = xfs_trans_alloc(mp, XFS_TRANS_REMOVE); 2159 if (is_dir) {
2160 tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR);
2161 log_count = XFS_DEFAULT_LOG_COUNT;
2162 } else {
2163 tp = xfs_trans_alloc(mp, XFS_TRANS_REMOVE);
2164 log_count = XFS_REMOVE_LOG_COUNT;
2165 }
2167 cancel_flags = XFS_TRANS_RELEASE_LOG_RES; 2166 cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
2167
2168 /* 2168 /*
2169 * We try to get the real space reservation first, 2169 * We try to get the real space reservation first,
2170 * allowing for directory btree deletion(s) implying 2170 * allowing for directory btree deletion(s) implying
@@ -2176,25 +2176,21 @@ xfs_remove(
2176 */ 2176 */
2177 resblks = XFS_REMOVE_SPACE_RES(mp); 2177 resblks = XFS_REMOVE_SPACE_RES(mp);
2178 error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0, 2178 error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0,
2179 XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT); 2179 XFS_TRANS_PERM_LOG_RES, log_count);
2180 if (error == ENOSPC) { 2180 if (error == ENOSPC) {
2181 resblks = 0; 2181 resblks = 0;
2182 error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0, 2182 error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0,
2183 XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT); 2183 XFS_TRANS_PERM_LOG_RES, log_count);
2184 } 2184 }
2185 if (error) { 2185 if (error) {
2186 ASSERT(error != ENOSPC); 2186 ASSERT(error != ENOSPC);
2187 REMOVE_DEBUG_TRACE(__LINE__); 2187 cancel_flags = 0;
2188 xfs_trans_cancel(tp, 0); 2188 goto out_trans_cancel;
2189 return error;
2190 } 2189 }
2191 2190
2192 error = xfs_lock_dir_and_entry(dp, ip); 2191 error = xfs_lock_dir_and_entry(dp, ip);
2193 if (error) { 2192 if (error)
2194 REMOVE_DEBUG_TRACE(__LINE__); 2193 goto out_trans_cancel;
2195 xfs_trans_cancel(tp, cancel_flags);
2196 goto std_return;
2197 }
2198 2194
2199 /* 2195 /*
2200 * At this point, we've gotten both the directory and the entry 2196 * At this point, we've gotten both the directory and the entry
@@ -2207,6 +2203,21 @@ xfs_remove(
2207 xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); 2203 xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
2208 2204
2209 /* 2205 /*
2206 * If we're removing a directory perform some additional validation.
2207 */
2208 if (is_dir) {
2209 ASSERT(ip->i_d.di_nlink >= 2);
2210 if (ip->i_d.di_nlink != 2) {
2211 error = XFS_ERROR(ENOTEMPTY);
2212 goto out_trans_cancel;
2213 }
2214 if (!xfs_dir_isempty(ip)) {
2215 error = XFS_ERROR(ENOTEMPTY);
2216 goto out_trans_cancel;
2217 }
2218 }
2219
2220 /*
2210 * Entry must exist since we did a lookup in xfs_lock_dir_and_entry. 2221 * Entry must exist since we did a lookup in xfs_lock_dir_and_entry.
2211 */ 2222 */
2212 XFS_BMAP_INIT(&free_list, &first_block); 2223 XFS_BMAP_INIT(&free_list, &first_block);
@@ -2214,39 +2225,64 @@ xfs_remove(
2214 &first_block, &free_list, resblks); 2225 &first_block, &free_list, resblks);
2215 if (error) { 2226 if (error) {
2216 ASSERT(error != ENOENT); 2227 ASSERT(error != ENOENT);
2217 REMOVE_DEBUG_TRACE(__LINE__); 2228 goto out_bmap_cancel;
2218 goto error1;
2219 } 2229 }
2220 xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); 2230 xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
2221 2231
2232 /*
2233 * Bump the in memory generation count on the parent
2234 * directory so that other can know that it has changed.
2235 */
2222 dp->i_gen++; 2236 dp->i_gen++;
2223 xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); 2237 xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
2224 2238
2225 error = xfs_droplink(tp, ip); 2239 if (is_dir) {
2226 if (error) { 2240 /*
2227 REMOVE_DEBUG_TRACE(__LINE__); 2241 * Drop the link from ip's "..".
2228 goto error1; 2242 */
2243 error = xfs_droplink(tp, dp);
2244 if (error)
2245 goto out_bmap_cancel;
2246
2247 /*
2248 * Drop the link from dp to ip.
2249 */
2250 error = xfs_droplink(tp, ip);
2251 if (error)
2252 goto out_bmap_cancel;
2253 } else {
2254 /*
2255 * When removing a non-directory we need to log the parent
2256 * inode here for the i_gen update. For a directory this is
2257 * done implicitly by the xfs_droplink call for the ".." entry.
2258 */
2259 xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
2229 } 2260 }
2230 2261
2231 /* Determine if this is the last link while 2262 /*
2263 * Drop the "." link from ip to self.
2264 */
2265 error = xfs_droplink(tp, ip);
2266 if (error)
2267 goto out_bmap_cancel;
2268
2269 /*
2270 * Determine if this is the last link while
2232 * we are in the transaction. 2271 * we are in the transaction.
2233 */ 2272 */
2234 link_zero = (ip)->i_d.di_nlink==0; 2273 link_zero = (ip->i_d.di_nlink == 0);
2235 2274
2236 /* 2275 /*
2237 * If this is a synchronous mount, make sure that the 2276 * If this is a synchronous mount, make sure that the
2238 * remove transaction goes to disk before returning to 2277 * remove transaction goes to disk before returning to
2239 * the user. 2278 * the user.
2240 */ 2279 */
2241 if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { 2280 if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
2242 xfs_trans_set_sync(tp); 2281 xfs_trans_set_sync(tp);
2243 }
2244 2282
2245 error = xfs_bmap_finish(&tp, &free_list, &committed); 2283 error = xfs_bmap_finish(&tp, &free_list, &committed);
2246 if (error) { 2284 if (error)
2247 REMOVE_DEBUG_TRACE(__LINE__); 2285 goto out_bmap_cancel;
2248 goto error_rele;
2249 }
2250 2286
2251 error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); 2287 error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
2252 if (error) 2288 if (error)
@@ -2258,38 +2294,26 @@ xfs_remove(
2258 * will get killed on last close in xfs_close() so we don't 2294 * will get killed on last close in xfs_close() so we don't
2259 * have to worry about that. 2295 * have to worry about that.
2260 */ 2296 */
2261 if (link_zero && xfs_inode_is_filestream(ip)) 2297 if (!is_dir && link_zero && xfs_inode_is_filestream(ip))
2262 xfs_filestream_deassociate(ip); 2298 xfs_filestream_deassociate(ip);
2263 2299
2264 xfs_itrace_exit(ip); 2300 xfs_itrace_exit(ip);
2301 xfs_itrace_exit(dp);
2265 2302
2266/* Fall through to std_return with error = 0 */
2267 std_return: 2303 std_return:
2268 if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTREMOVE)) { 2304 if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTREMOVE)) {
2269 (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE, 2305 XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE, dp, DM_RIGHT_NULL,
2270 dp, DM_RIGHT_NULL, 2306 NULL, DM_RIGHT_NULL, name->name, NULL,
2271 NULL, DM_RIGHT_NULL, 2307 ip->i_d.di_mode, error, 0);
2272 name->name, NULL, ip->i_d.di_mode, error, 0);
2273 } 2308 }
2274 return error;
2275 2309
2276 error1: 2310 return error;
2277 xfs_bmap_cancel(&free_list);
2278 cancel_flags |= XFS_TRANS_ABORT;
2279 xfs_trans_cancel(tp, cancel_flags);
2280 goto std_return;
2281 2311
2282 error_rele: 2312 out_bmap_cancel:
2283 /*
2284 * In this case make sure to not release the inode until after
2285 * the current transaction is aborted. Releasing it beforehand
2286 * can cause us to go to xfs_inactive and start a recursive
2287 * transaction which can easily deadlock with the current one.
2288 */
2289 xfs_bmap_cancel(&free_list); 2313 xfs_bmap_cancel(&free_list);
2290 cancel_flags |= XFS_TRANS_ABORT; 2314 cancel_flags |= XFS_TRANS_ABORT;
2315 out_trans_cancel:
2291 xfs_trans_cancel(tp, cancel_flags); 2316 xfs_trans_cancel(tp, cancel_flags);
2292
2293 goto std_return; 2317 goto std_return;
2294} 2318}
2295 2319
@@ -2656,186 +2680,6 @@ std_return:
2656} 2680}
2657 2681
2658int 2682int
2659xfs_rmdir(
2660 xfs_inode_t *dp,
2661 struct xfs_name *name,
2662 xfs_inode_t *cdp)
2663{
2664 xfs_mount_t *mp = dp->i_mount;
2665 xfs_trans_t *tp;
2666 int error;
2667 xfs_bmap_free_t free_list;
2668 xfs_fsblock_t first_block;
2669 int cancel_flags;
2670 int committed;
2671 int last_cdp_link;
2672 uint resblks;
2673
2674 xfs_itrace_entry(dp);
2675
2676 if (XFS_FORCED_SHUTDOWN(mp))
2677 return XFS_ERROR(EIO);
2678
2679 if (DM_EVENT_ENABLED(dp, DM_EVENT_REMOVE)) {
2680 error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE,
2681 dp, DM_RIGHT_NULL,
2682 NULL, DM_RIGHT_NULL, name->name,
2683 NULL, cdp->i_d.di_mode, 0, 0);
2684 if (error)
2685 return XFS_ERROR(error);
2686 }
2687
2688 /*
2689 * Get the dquots for the inodes.
2690 */
2691 error = XFS_QM_DQATTACH(mp, dp, 0);
2692 if (!error)
2693 error = XFS_QM_DQATTACH(mp, cdp, 0);
2694 if (error) {
2695 REMOVE_DEBUG_TRACE(__LINE__);
2696 goto std_return;
2697 }
2698
2699 tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR);
2700 cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
2701 /*
2702 * We try to get the real space reservation first,
2703 * allowing for directory btree deletion(s) implying
2704 * possible bmap insert(s). If we can't get the space
2705 * reservation then we use 0 instead, and avoid the bmap
2706 * btree insert(s) in the directory code by, if the bmap
2707 * insert tries to happen, instead trimming the LAST
2708 * block from the directory.
2709 */
2710 resblks = XFS_REMOVE_SPACE_RES(mp);
2711 error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0,
2712 XFS_TRANS_PERM_LOG_RES, XFS_DEFAULT_LOG_COUNT);
2713 if (error == ENOSPC) {
2714 resblks = 0;
2715 error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0,
2716 XFS_TRANS_PERM_LOG_RES, XFS_DEFAULT_LOG_COUNT);
2717 }
2718 if (error) {
2719 ASSERT(error != ENOSPC);
2720 cancel_flags = 0;
2721 goto error_return;
2722 }
2723 XFS_BMAP_INIT(&free_list, &first_block);
2724
2725 /*
2726 * Now lock the child directory inode and the parent directory
2727 * inode in the proper order. This will take care of validating
2728 * that the directory entry for the child directory inode has
2729 * not changed while we were obtaining a log reservation.
2730 */
2731 error = xfs_lock_dir_and_entry(dp, cdp);
2732 if (error) {
2733 xfs_trans_cancel(tp, cancel_flags);
2734 goto std_return;
2735 }
2736
2737 IHOLD(dp);
2738 xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
2739
2740 IHOLD(cdp);
2741 xfs_trans_ijoin(tp, cdp, XFS_ILOCK_EXCL);
2742
2743 ASSERT(cdp->i_d.di_nlink >= 2);
2744 if (cdp->i_d.di_nlink != 2) {
2745 error = XFS_ERROR(ENOTEMPTY);
2746 goto error_return;
2747 }
2748 if (!xfs_dir_isempty(cdp)) {
2749 error = XFS_ERROR(ENOTEMPTY);
2750 goto error_return;
2751 }
2752
2753 error = xfs_dir_removename(tp, dp, name, cdp->i_ino,
2754 &first_block, &free_list, resblks);
2755 if (error)
2756 goto error1;
2757
2758 xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
2759
2760 /*
2761 * Bump the in memory generation count on the parent
2762 * directory so that other can know that it has changed.
2763 */
2764 dp->i_gen++;
2765
2766 /*
2767 * Drop the link from cdp's "..".
2768 */
2769 error = xfs_droplink(tp, dp);
2770 if (error) {
2771 goto error1;
2772 }
2773
2774 /*
2775 * Drop the link from dp to cdp.
2776 */
2777 error = xfs_droplink(tp, cdp);
2778 if (error) {
2779 goto error1;
2780 }
2781
2782 /*
2783 * Drop the "." link from cdp to self.
2784 */
2785 error = xfs_droplink(tp, cdp);
2786 if (error) {
2787 goto error1;
2788 }
2789
2790 /* Determine these before committing transaction */
2791 last_cdp_link = (cdp)->i_d.di_nlink==0;
2792
2793 /*
2794 * If this is a synchronous mount, make sure that the
2795 * rmdir transaction goes to disk before returning to
2796 * the user.
2797 */
2798 if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
2799 xfs_trans_set_sync(tp);
2800 }
2801
2802 error = xfs_bmap_finish (&tp, &free_list, &committed);
2803 if (error) {
2804 xfs_bmap_cancel(&free_list);
2805 xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES |
2806 XFS_TRANS_ABORT));
2807 goto std_return;
2808 }
2809
2810 error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
2811 if (error) {
2812 goto std_return;
2813 }
2814
2815
2816 /* Fall through to std_return with error = 0 or the errno
2817 * from xfs_trans_commit. */
2818 std_return:
2819 if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTREMOVE)) {
2820 (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE,
2821 dp, DM_RIGHT_NULL,
2822 NULL, DM_RIGHT_NULL,
2823 name->name, NULL, cdp->i_d.di_mode,
2824 error, 0);
2825 }
2826 return error;
2827
2828 error1:
2829 xfs_bmap_cancel(&free_list);
2830 cancel_flags |= XFS_TRANS_ABORT;
2831 /* FALLTHROUGH */
2832
2833 error_return:
2834 xfs_trans_cancel(tp, cancel_flags);
2835 goto std_return;
2836}
2837
2838int
2839xfs_symlink( 2683xfs_symlink(
2840 xfs_inode_t *dp, 2684 xfs_inode_t *dp,
2841 struct xfs_name *link_name, 2685 struct xfs_name *link_name,