diff options
Diffstat (limited to 'fs/xfs/xfs_rename.c')
| -rw-r--r-- | fs/xfs/xfs_rename.c | 252 |
1 files changed, 51 insertions, 201 deletions
diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c index ee371890d85d..d8063e1ad298 100644 --- a/fs/xfs/xfs_rename.c +++ b/fs/xfs/xfs_rename.c | |||
| @@ -55,85 +55,32 @@ xfs_rename_unlock4( | |||
| 55 | 55 | ||
| 56 | xfs_iunlock(i_tab[0], lock_mode); | 56 | xfs_iunlock(i_tab[0], lock_mode); |
| 57 | for (i = 1; i < 4; i++) { | 57 | for (i = 1; i < 4; i++) { |
| 58 | if (i_tab[i] == NULL) { | 58 | if (i_tab[i] == NULL) |
| 59 | break; | 59 | break; |
| 60 | } | 60 | |
| 61 | /* | 61 | /* |
| 62 | * Watch out for duplicate entries in the table. | 62 | * Watch out for duplicate entries in the table. |
| 63 | */ | 63 | */ |
| 64 | if (i_tab[i] != i_tab[i-1]) { | 64 | if (i_tab[i] != i_tab[i-1]) |
| 65 | xfs_iunlock(i_tab[i], lock_mode); | 65 | xfs_iunlock(i_tab[i], lock_mode); |
| 66 | } | ||
| 67 | } | 66 | } |
| 68 | } | 67 | } |
| 69 | 68 | ||
| 70 | #ifdef DEBUG | ||
| 71 | int xfs_rename_skip, xfs_rename_nskip; | ||
| 72 | #endif | ||
| 73 | |||
| 74 | /* | 69 | /* |
| 75 | * The following routine will acquire the locks required for a rename | 70 | * Enter all inodes for a rename transaction into a sorted array. |
| 76 | * operation. The code understands the semantics of renames and will | ||
| 77 | * validate that name1 exists under dp1 & that name2 may or may not | ||
| 78 | * exist under dp2. | ||
| 79 | * | ||
| 80 | * We are renaming dp1/name1 to dp2/name2. | ||
| 81 | * | ||
| 82 | * Return ENOENT if dp1 does not exist, other lookup errors, or 0 for success. | ||
| 83 | */ | 71 | */ |
| 84 | STATIC int | 72 | STATIC void |
| 85 | xfs_lock_for_rename( | 73 | xfs_sort_for_rename( |
| 86 | xfs_inode_t *dp1, /* in: old (source) directory inode */ | 74 | xfs_inode_t *dp1, /* in: old (source) directory inode */ |
| 87 | xfs_inode_t *dp2, /* in: new (target) directory inode */ | 75 | xfs_inode_t *dp2, /* in: new (target) directory inode */ |
| 88 | xfs_inode_t *ip1, /* in: inode of old entry */ | 76 | xfs_inode_t *ip1, /* in: inode of old entry */ |
| 89 | struct xfs_name *name2, /* in: new entry name */ | 77 | xfs_inode_t *ip2, /* in: inode of new entry, if it |
| 90 | xfs_inode_t **ipp2, /* out: inode of new entry, if it | ||
| 91 | already exists, NULL otherwise. */ | 78 | already exists, NULL otherwise. */ |
| 92 | xfs_inode_t **i_tab,/* out: array of inode returned, sorted */ | 79 | xfs_inode_t **i_tab,/* out: array of inode returned, sorted */ |
| 93 | int *num_inodes) /* out: number of inodes in array */ | 80 | int *num_inodes) /* out: number of inodes in array */ |
| 94 | { | 81 | { |
| 95 | xfs_inode_t *ip2 = NULL; | ||
| 96 | xfs_inode_t *temp; | 82 | xfs_inode_t *temp; |
| 97 | xfs_ino_t inum1, inum2; | ||
| 98 | int error; | ||
| 99 | int i, j; | 83 | int i, j; |
| 100 | uint lock_mode; | ||
| 101 | int diff_dirs = (dp1 != dp2); | ||
| 102 | |||
| 103 | /* | ||
| 104 | * First, find out the current inums of the entries so that we | ||
| 105 | * can determine the initial locking order. We'll have to | ||
| 106 | * sanity check stuff after all the locks have been acquired | ||
| 107 | * to see if we still have the right inodes, directories, etc. | ||
| 108 | */ | ||
| 109 | lock_mode = xfs_ilock_map_shared(dp1); | ||
| 110 | IHOLD(ip1); | ||
| 111 | xfs_itrace_ref(ip1); | ||
| 112 | |||
| 113 | inum1 = ip1->i_ino; | ||
| 114 | |||
| 115 | /* | ||
| 116 | * Unlock dp1 and lock dp2 if they are different. | ||
| 117 | */ | ||
| 118 | if (diff_dirs) { | ||
| 119 | xfs_iunlock_map_shared(dp1, lock_mode); | ||
| 120 | lock_mode = xfs_ilock_map_shared(dp2); | ||
| 121 | } | ||
| 122 | |||
| 123 | error = xfs_dir_lookup_int(dp2, lock_mode, name2, &inum2, &ip2); | ||
| 124 | if (error == ENOENT) { /* target does not need to exist. */ | ||
| 125 | inum2 = 0; | ||
| 126 | } else if (error) { | ||
| 127 | /* | ||
| 128 | * If dp2 and dp1 are the same, the next line unlocks dp1. | ||
| 129 | * Got it? | ||
| 130 | */ | ||
| 131 | xfs_iunlock_map_shared(dp2, lock_mode); | ||
| 132 | IRELE (ip1); | ||
| 133 | return error; | ||
| 134 | } else { | ||
| 135 | xfs_itrace_ref(ip2); | ||
| 136 | } | ||
| 137 | 84 | ||
| 138 | /* | 85 | /* |
| 139 | * i_tab contains a list of pointers to inodes. We initialize | 86 | * i_tab contains a list of pointers to inodes. We initialize |
| @@ -145,21 +92,20 @@ xfs_lock_for_rename( | |||
| 145 | i_tab[0] = dp1; | 92 | i_tab[0] = dp1; |
| 146 | i_tab[1] = dp2; | 93 | i_tab[1] = dp2; |
| 147 | i_tab[2] = ip1; | 94 | i_tab[2] = ip1; |
| 148 | if (inum2 == 0) { | 95 | if (ip2) { |
| 149 | *num_inodes = 3; | ||
| 150 | i_tab[3] = NULL; | ||
| 151 | } else { | ||
| 152 | *num_inodes = 4; | 96 | *num_inodes = 4; |
| 153 | i_tab[3] = ip2; | 97 | i_tab[3] = ip2; |
| 98 | } else { | ||
| 99 | *num_inodes = 3; | ||
| 100 | i_tab[3] = NULL; | ||
| 154 | } | 101 | } |
| 155 | *ipp2 = i_tab[3]; | ||
| 156 | 102 | ||
| 157 | /* | 103 | /* |
| 158 | * Sort the elements via bubble sort. (Remember, there are at | 104 | * Sort the elements via bubble sort. (Remember, there are at |
| 159 | * most 4 elements to sort, so this is adequate.) | 105 | * most 4 elements to sort, so this is adequate.) |
| 160 | */ | 106 | */ |
| 161 | for (i=0; i < *num_inodes; i++) { | 107 | for (i = 0; i < *num_inodes; i++) { |
| 162 | for (j=1; j < *num_inodes; j++) { | 108 | for (j = 1; j < *num_inodes; j++) { |
| 163 | if (i_tab[j]->i_ino < i_tab[j-1]->i_ino) { | 109 | if (i_tab[j]->i_ino < i_tab[j-1]->i_ino) { |
| 164 | temp = i_tab[j]; | 110 | temp = i_tab[j]; |
| 165 | i_tab[j] = i_tab[j-1]; | 111 | i_tab[j] = i_tab[j-1]; |
| @@ -167,30 +113,6 @@ xfs_lock_for_rename( | |||
| 167 | } | 113 | } |
| 168 | } | 114 | } |
| 169 | } | 115 | } |
| 170 | |||
| 171 | /* | ||
| 172 | * We have dp2 locked. If it isn't first, unlock it. | ||
| 173 | * If it is first, tell xfs_lock_inodes so it can skip it | ||
| 174 | * when locking. if dp1 == dp2, xfs_lock_inodes will skip both | ||
| 175 | * since they are equal. xfs_lock_inodes needs all these inodes | ||
| 176 | * so that it can unlock and retry if there might be a dead-lock | ||
| 177 | * potential with the log. | ||
| 178 | */ | ||
| 179 | |||
| 180 | if (i_tab[0] == dp2 && lock_mode == XFS_ILOCK_SHARED) { | ||
| 181 | #ifdef DEBUG | ||
| 182 | xfs_rename_skip++; | ||
| 183 | #endif | ||
| 184 | xfs_lock_inodes(i_tab, *num_inodes, 1, XFS_ILOCK_SHARED); | ||
| 185 | } else { | ||
| 186 | #ifdef DEBUG | ||
| 187 | xfs_rename_nskip++; | ||
| 188 | #endif | ||
| 189 | xfs_iunlock_map_shared(dp2, lock_mode); | ||
| 190 | xfs_lock_inodes(i_tab, *num_inodes, 0, XFS_ILOCK_SHARED); | ||
| 191 | } | ||
| 192 | |||
| 193 | return 0; | ||
| 194 | } | 116 | } |
| 195 | 117 | ||
| 196 | /* | 118 | /* |
| @@ -202,10 +124,10 @@ xfs_rename( | |||
| 202 | struct xfs_name *src_name, | 124 | struct xfs_name *src_name, |
| 203 | xfs_inode_t *src_ip, | 125 | xfs_inode_t *src_ip, |
| 204 | xfs_inode_t *target_dp, | 126 | xfs_inode_t *target_dp, |
| 205 | struct xfs_name *target_name) | 127 | struct xfs_name *target_name, |
| 128 | xfs_inode_t *target_ip) | ||
| 206 | { | 129 | { |
| 207 | xfs_trans_t *tp; | 130 | xfs_trans_t *tp = NULL; |
| 208 | xfs_inode_t *target_ip; | ||
| 209 | xfs_mount_t *mp = src_dp->i_mount; | 131 | xfs_mount_t *mp = src_dp->i_mount; |
| 210 | int new_parent; /* moving to a new dir */ | 132 | int new_parent; /* moving to a new dir */ |
| 211 | int src_is_directory; /* src_name is a directory */ | 133 | int src_is_directory; /* src_name is a directory */ |
| @@ -215,9 +137,7 @@ xfs_rename( | |||
| 215 | int cancel_flags; | 137 | int cancel_flags; |
| 216 | int committed; | 138 | int committed; |
| 217 | xfs_inode_t *inodes[4]; | 139 | xfs_inode_t *inodes[4]; |
| 218 | int target_ip_dropped = 0; /* dropped target_ip link? */ | ||
| 219 | int spaceres; | 140 | int spaceres; |
| 220 | int target_link_zero = 0; | ||
| 221 | int num_inodes; | 141 | int num_inodes; |
| 222 | 142 | ||
| 223 | xfs_itrace_entry(src_dp); | 143 | xfs_itrace_entry(src_dp); |
| @@ -230,64 +150,27 @@ xfs_rename( | |||
| 230 | target_dp, DM_RIGHT_NULL, | 150 | target_dp, DM_RIGHT_NULL, |
| 231 | src_name->name, target_name->name, | 151 | src_name->name, target_name->name, |
| 232 | 0, 0, 0); | 152 | 0, 0, 0); |
| 233 | if (error) { | 153 | if (error) |
| 234 | return error; | 154 | return error; |
| 235 | } | ||
| 236 | } | 155 | } |
| 237 | /* Return through std_return after this point. */ | 156 | /* Return through std_return after this point. */ |
| 238 | 157 | ||
| 239 | /* | 158 | new_parent = (src_dp != target_dp); |
| 240 | * Lock all the participating inodes. Depending upon whether | 159 | src_is_directory = ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR); |
| 241 | * the target_name exists in the target directory, and | ||
| 242 | * whether the target directory is the same as the source | ||
| 243 | * directory, we can lock from 2 to 4 inodes. | ||
| 244 | * xfs_lock_for_rename() will return ENOENT if src_name | ||
| 245 | * does not exist in the source directory. | ||
| 246 | */ | ||
| 247 | tp = NULL; | ||
| 248 | error = xfs_lock_for_rename(src_dp, target_dp, src_ip, target_name, | ||
| 249 | &target_ip, inodes, &num_inodes); | ||
| 250 | if (error) { | ||
| 251 | /* | ||
| 252 | * We have nothing locked, no inode references, and | ||
| 253 | * no transaction, so just get out. | ||
| 254 | */ | ||
| 255 | goto std_return; | ||
| 256 | } | ||
| 257 | |||
| 258 | ASSERT(src_ip != NULL); | ||
| 259 | 160 | ||
| 260 | if ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR) { | 161 | if (src_is_directory) { |
| 261 | /* | 162 | /* |
| 262 | * Check for link count overflow on target_dp | 163 | * Check for link count overflow on target_dp |
| 263 | */ | 164 | */ |
| 264 | if (target_ip == NULL && (src_dp != target_dp) && | 165 | if (target_ip == NULL && new_parent && |
| 265 | target_dp->i_d.di_nlink >= XFS_MAXLINK) { | 166 | target_dp->i_d.di_nlink >= XFS_MAXLINK) { |
| 266 | error = XFS_ERROR(EMLINK); | 167 | error = XFS_ERROR(EMLINK); |
| 267 | xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED); | 168 | goto std_return; |
| 268 | goto rele_return; | ||
| 269 | } | 169 | } |
| 270 | } | 170 | } |
| 271 | 171 | ||
| 272 | /* | 172 | xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip, |
| 273 | * If we are using project inheritance, we only allow renames | 173 | inodes, &num_inodes); |
| 274 | * into our tree when the project IDs are the same; else the | ||
| 275 | * tree quota mechanism would be circumvented. | ||
| 276 | */ | ||
| 277 | if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) && | ||
| 278 | (target_dp->i_d.di_projid != src_ip->i_d.di_projid))) { | ||
| 279 | error = XFS_ERROR(EXDEV); | ||
| 280 | xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED); | ||
| 281 | goto rele_return; | ||
| 282 | } | ||
| 283 | |||
| 284 | new_parent = (src_dp != target_dp); | ||
| 285 | src_is_directory = ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR); | ||
| 286 | |||
| 287 | /* | ||
| 288 | * Drop the locks on our inodes so that we can start the transaction. | ||
| 289 | */ | ||
| 290 | xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED); | ||
| 291 | 174 | ||
| 292 | XFS_BMAP_INIT(&free_list, &first_block); | 175 | XFS_BMAP_INIT(&free_list, &first_block); |
| 293 | tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME); | 176 | tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME); |
| @@ -302,7 +185,7 @@ xfs_rename( | |||
| 302 | } | 185 | } |
| 303 | if (error) { | 186 | if (error) { |
| 304 | xfs_trans_cancel(tp, 0); | 187 | xfs_trans_cancel(tp, 0); |
| 305 | goto rele_return; | 188 | goto std_return; |
| 306 | } | 189 | } |
| 307 | 190 | ||
| 308 | /* | 191 | /* |
| @@ -310,13 +193,29 @@ xfs_rename( | |||
| 310 | */ | 193 | */ |
| 311 | if ((error = XFS_QM_DQVOPRENAME(mp, inodes))) { | 194 | if ((error = XFS_QM_DQVOPRENAME(mp, inodes))) { |
| 312 | xfs_trans_cancel(tp, cancel_flags); | 195 | xfs_trans_cancel(tp, cancel_flags); |
| 313 | goto rele_return; | 196 | goto std_return; |
| 314 | } | 197 | } |
| 315 | 198 | ||
| 316 | /* | 199 | /* |
| 317 | * Reacquire the inode locks we dropped above. | 200 | * Lock all the participating inodes. Depending upon whether |
| 201 | * the target_name exists in the target directory, and | ||
| 202 | * whether the target directory is the same as the source | ||
| 203 | * directory, we can lock from 2 to 4 inodes. | ||
| 204 | */ | ||
| 205 | xfs_lock_inodes(inodes, num_inodes, XFS_ILOCK_EXCL); | ||
| 206 | |||
| 207 | /* | ||
| 208 | * If we are using project inheritance, we only allow renames | ||
| 209 | * into our tree when the project IDs are the same; else the | ||
| 210 | * tree quota mechanism would be circumvented. | ||
| 318 | */ | 211 | */ |
| 319 | xfs_lock_inodes(inodes, num_inodes, 0, XFS_ILOCK_EXCL); | 212 | if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) && |
| 213 | (target_dp->i_d.di_projid != src_ip->i_d.di_projid))) { | ||
| 214 | error = XFS_ERROR(EXDEV); | ||
| 215 | xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED); | ||
| 216 | xfs_trans_cancel(tp, cancel_flags); | ||
| 217 | goto std_return; | ||
| 218 | } | ||
| 320 | 219 | ||
| 321 | /* | 220 | /* |
| 322 | * Join all the inodes to the transaction. From this point on, | 221 | * Join all the inodes to the transaction. From this point on, |
| @@ -328,17 +227,17 @@ xfs_rename( | |||
| 328 | */ | 227 | */ |
| 329 | IHOLD(src_dp); | 228 | IHOLD(src_dp); |
| 330 | xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL); | 229 | xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL); |
| 230 | |||
| 331 | if (new_parent) { | 231 | if (new_parent) { |
| 332 | IHOLD(target_dp); | 232 | IHOLD(target_dp); |
| 333 | xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL); | 233 | xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL); |
| 334 | } | 234 | } |
| 335 | if ((src_ip != src_dp) && (src_ip != target_dp)) { | 235 | |
| 336 | xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL); | 236 | IHOLD(src_ip); |
| 337 | } | 237 | xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL); |
| 338 | if ((target_ip != NULL) && | 238 | |
| 339 | (target_ip != src_ip) && | 239 | if (target_ip) { |
| 340 | (target_ip != src_dp) && | 240 | IHOLD(target_ip); |
| 341 | (target_ip != target_dp)) { | ||
| 342 | xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL); | 241 | xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL); |
| 343 | } | 242 | } |
| 344 | 243 | ||
| @@ -412,7 +311,6 @@ xfs_rename( | |||
| 412 | error = xfs_droplink(tp, target_ip); | 311 | error = xfs_droplink(tp, target_ip); |
| 413 | if (error) | 312 | if (error) |
| 414 | goto abort_return; | 313 | goto abort_return; |
| 415 | target_ip_dropped = 1; | ||
| 416 | 314 | ||
| 417 | if (src_is_directory) { | 315 | if (src_is_directory) { |
| 418 | /* | 316 | /* |
| @@ -422,10 +320,6 @@ xfs_rename( | |||
| 422 | if (error) | 320 | if (error) |
| 423 | goto abort_return; | 321 | goto abort_return; |
| 424 | } | 322 | } |
| 425 | |||
| 426 | /* Do this test while we still hold the locks */ | ||
| 427 | target_link_zero = (target_ip)->i_d.di_nlink==0; | ||
| 428 | |||
| 429 | } /* target_ip != NULL */ | 323 | } /* target_ip != NULL */ |
| 430 | 324 | ||
| 431 | /* | 325 | /* |
| @@ -492,15 +386,6 @@ xfs_rename( | |||
| 492 | } | 386 | } |
| 493 | 387 | ||
| 494 | /* | 388 | /* |
| 495 | * If there was a target inode, take an extra reference on | ||
| 496 | * it here so that it doesn't go to xfs_inactive() from | ||
| 497 | * within the commit. | ||
| 498 | */ | ||
| 499 | if (target_ip != NULL) { | ||
| 500 | IHOLD(target_ip); | ||
| 501 | } | ||
| 502 | |||
| 503 | /* | ||
| 504 | * If this is a synchronous mount, make sure that the | 389 | * If this is a synchronous mount, make sure that the |
| 505 | * rename transaction goes to disk before returning to | 390 | * rename transaction goes to disk before returning to |
| 506 | * the user. | 391 | * the user. |
| @@ -509,30 +394,11 @@ xfs_rename( | |||
| 509 | xfs_trans_set_sync(tp); | 394 | xfs_trans_set_sync(tp); |
| 510 | } | 395 | } |
| 511 | 396 | ||
| 512 | /* | ||
| 513 | * Take refs. for vop_link_removed calls below. No need to worry | ||
| 514 | * about directory refs. because the caller holds them. | ||
| 515 | * | ||
| 516 | * Do holds before the xfs_bmap_finish since it might rele them down | ||
| 517 | * to zero. | ||
| 518 | */ | ||
| 519 | |||
| 520 | if (target_ip_dropped) | ||
| 521 | IHOLD(target_ip); | ||
| 522 | IHOLD(src_ip); | ||
| 523 | |||
| 524 | error = xfs_bmap_finish(&tp, &free_list, &committed); | 397 | error = xfs_bmap_finish(&tp, &free_list, &committed); |
| 525 | if (error) { | 398 | if (error) { |
| 526 | xfs_bmap_cancel(&free_list); | 399 | xfs_bmap_cancel(&free_list); |
| 527 | xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | | 400 | xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | |
| 528 | XFS_TRANS_ABORT)); | 401 | XFS_TRANS_ABORT)); |
| 529 | if (target_ip != NULL) { | ||
| 530 | IRELE(target_ip); | ||
| 531 | } | ||
| 532 | if (target_ip_dropped) { | ||
| 533 | IRELE(target_ip); | ||
| 534 | } | ||
| 535 | IRELE(src_ip); | ||
| 536 | goto std_return; | 402 | goto std_return; |
| 537 | } | 403 | } |
| 538 | 404 | ||
| @@ -541,15 +407,6 @@ xfs_rename( | |||
| 541 | * the vnode references. | 407 | * the vnode references. |
| 542 | */ | 408 | */ |
| 543 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | 409 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); |
| 544 | if (target_ip != NULL) | ||
| 545 | IRELE(target_ip); | ||
| 546 | /* | ||
| 547 | * Let interposed file systems know about removed links. | ||
| 548 | */ | ||
| 549 | if (target_ip_dropped) | ||
| 550 | IRELE(target_ip); | ||
| 551 | |||
| 552 | IRELE(src_ip); | ||
| 553 | 410 | ||
| 554 | /* Fall through to std_return with error = 0 or errno from | 411 | /* Fall through to std_return with error = 0 or errno from |
| 555 | * xfs_trans_commit */ | 412 | * xfs_trans_commit */ |
| @@ -571,11 +428,4 @@ std_return: | |||
| 571 | xfs_bmap_cancel(&free_list); | 428 | xfs_bmap_cancel(&free_list); |
| 572 | xfs_trans_cancel(tp, cancel_flags); | 429 | xfs_trans_cancel(tp, cancel_flags); |
| 573 | goto std_return; | 430 | goto std_return; |
| 574 | |||
| 575 | rele_return: | ||
| 576 | IRELE(src_ip); | ||
| 577 | if (target_ip != NULL) { | ||
| 578 | IRELE(target_ip); | ||
| 579 | } | ||
| 580 | goto std_return; | ||
| 581 | } | 431 | } |
