77
76
/* true if old FS format...*/
78
77
#define OFSFMT(vp) ((vp)->v_mount->mnt_maxsymlinklen <= 0)
80
static int ufs_lookup_(struct vnode *, struct vnode **, struct componentname *,
85
81
ufs_lookup_upgrade_lock(struct vnode *vp)
218
return (ufs_lookup_(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL));
214
return (ufs_lookup_ino(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL));
222
ufs_lookup_(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp,
218
ufs_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp,
225
221
struct inode *dp; /* inode for directory being searched */
579
579
if ((flags & ISLASTCN) && nameiop == LOOKUP)
580
580
dp->i_diroff = i_offset &~ (DIRBLKSIZ - 1);
582
if (dd_ino != NULL) {
588
583
* If deleting, and at end of pathname, return
589
584
* parameters which can be used to remove file.
591
586
if (nameiop == DELETE && (flags & ISLASTCN)) {
592
587
if (flags & LOCKPARENT)
593
588
ASSERT_VOP_ELOCKED(vdp, __FUNCTION__);
594
if ((error = VFS_VGET(vdp->v_mount, ino,
595
LK_EXCLUSIVE, &tdp)) != 0)
598
error = ufs_delete_denied(vdp, tdp, cred, cnp->cn_thread);
606
590
* Return pointer to current entry in dp->i_offset,
607
591
* and distance past previous entry (if there
620
604
dp->i_count = dp->i_offset - prevoff;
607
if ((error = VFS_VGET(vdp->v_mount, ino,
608
LK_EXCLUSIVE, &tdp)) != 0)
610
error = ufs_delete_denied(vdp, tdp, cred, cnp->cn_thread);
621
615
if (dp->i_number == ino) {
714
712
* to the inode we looked up before vdp lock was
717
error = ufs_lookup_(pdp, NULL, cnp, &ino1);
715
error = ufs_lookup_ino(pdp, NULL, cnp, &ino1);
866
864
* soft dependency code).
869
ufs_direnter(dvp, tvp, dirp, cnp, newdirbp)
867
ufs_direnter(dvp, tvp, dirp, cnp, newdirbp, isrename)
870
868
struct vnode *dvp;
871
869
struct vnode *tvp;
872
870
struct direct *dirp;
873
871
struct componentname *cnp;
874
872
struct buf *newdirbp;
876
875
struct ucred *cr;
877
876
struct thread *td;
944
943
blkoff += DIRBLKSIZ;
946
945
if (softdep_setup_directory_add(bp, dp, dp->i_offset,
947
dirp->d_ino, newdirbp, 1) == 0) {
946
dirp->d_ino, newdirbp, 1))
947
dp->i_flag |= IN_NEEDSYNC;
951
if ((dp->i_flag & IN_NEEDSYNC) == 0)
949
952
return (UFS_UPDATE(dvp, 0));
951
/* We have just allocated a directory block in an
952
* indirect block. Rather than tracking when it gets
953
* claimed by the inode, we simply do a VOP_FSYNC
954
* now to ensure that it is there (in case the user
955
* does a future fsync). Note that we have to unlock
956
* the inode for the entry that we just entered, as
957
* the VOP_FSYNC may need to lock other inodes which
958
* can lead to deadlock if we also hold a lock on
959
* the newly entered node.
954
* We have just allocated a directory block in an
955
* indirect block. We must prevent holes in the
956
* directory created if directory entries are
957
* written out of order. To accomplish this we
958
* fsync when we extend a directory into indirects.
959
* During rename it's not safe to drop the tvp lock
960
* so sync must be delayed until it is.
962
* This synchronous step could be removed if fsck and
963
* the kernel were taught to fill in sparse
964
* directories rather than panic.
961
if ((error = bwrite(bp)))
964
969
VOP_UNLOCK(tvp, 0);
965
error = VOP_FSYNC(dvp, MNT_WAIT, td);
970
(void) VOP_FSYNC(dvp, MNT_WAIT, td);
967
972
vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
1048
1053
dp->i_offset + ((char *)ep - dirbuf));
1050
1055
if (DOINGSOFTDEP(dvp))
1051
softdep_change_directoryentry_offset(dp, dirbuf,
1056
softdep_change_directoryentry_offset(bp, dp, dirbuf,
1052
1057
(caddr_t)nep, (caddr_t)ep, dsize);
1054
1059
bcopy((caddr_t)nep, (caddr_t)ep, dsize);
1100
1105
(void) softdep_setup_directory_add(bp, dp,
1101
1106
dp->i_offset + (caddr_t)ep - dirbuf,
1102
1107
dirp->d_ino, newdirbp, 0);
1108
if (newdirbp != NULL)
1105
1112
if (DOINGASYNC(dvp)) {
1117
1124
* lock other inodes which can lead to deadlock if we also hold a
1118
1125
* lock on the newly entered node.
1120
if (error == 0 && dp->i_endoff && dp->i_endoff < dp->i_size) {
1127
if (isrename == 0 && error == 0 &&
1128
dp->i_endoff && dp->i_endoff < dp->i_size) {
1121
1129
if (tvp != NULL)
1122
1130
VOP_UNLOCK(tvp, 0);
1123
1131
#ifdef UFS_DIRHASH
1159
1167
dp = VTOI(dvp);
1170
* Adjust the link count early so softdep can block if necessary.
1174
if (DOINGSOFTDEP(dvp)) {
1175
softdep_setup_unlink(dp, ip);
1178
DIP_SET(ip, i_nlink, ip->i_nlink);
1179
ip->i_flag |= IN_CHANGE;
1161
1182
if (flags & DOWHITEOUT) {
1163
1184
* Whiteout entry: set d_ino to WINO.
1187
1208
if (dp->i_dirhash != NULL)
1188
1209
ufsdirhash_remove(dp, rep, dp->i_offset);
1211
if (ip && rep->d_ino != ip->i_number)
1212
panic("ufs_dirremove: ip %d does not match dirent ino %d\n",
1213
ip->i_number, rep->d_ino);
1190
1214
if (dp->i_count == 0) {
1192
1216
* First entry in block: set d_ino to zero.
1205
1229
dp->i_offset & ~(DIRBLKSIZ - 1));
1208
1233
if (DOINGSOFTDEP(dvp)) {
1211
softdep_change_linkcnt(ip);
1212
1235
softdep_setup_remove(bp, dp, ip, isrmdir);
1214
if (softdep_slowdown(dvp)) {
1236
if (softdep_slowdown(dvp))
1215
1237
error = bwrite(bp);
1224
DIP_SET(ip, i_nlink, ip->i_nlink);
1225
ip->i_flag |= IN_CHANGE;
1227
1241
if (flags & DOWHITEOUT)
1228
1242
error = bwrite(bp);
1229
else if (DOINGASYNC(dvp) && dp->i_count != 0) {
1243
else if (DOINGASYNC(dvp) && dp->i_count != 0)
1233
1246
error = bwrite(bp);
1235
1248
dp->i_flag |= IN_CHANGE | IN_UPDATE;
1262
1273
struct vnode *vdp = ITOV(dp);
1277
* Drop the link before we lock the buf so softdep can block if
1281
if (DOINGSOFTDEP(vdp)) {
1282
softdep_setup_unlink(dp, oip);
1285
DIP_SET(oip, i_nlink, oip->i_nlink);
1286
oip->i_flag |= IN_CHANGE;
1265
1289
error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp);
1267
1291
return (error);
1292
if (ep->d_namlen == 2 && ep->d_name[1] == '.' && ep->d_name[0] == '.' &&
1293
ep->d_ino != oip->i_number) {
1268
1297
ep->d_ino = newinum;
1269
1298
if (!OFSFMT(vdp))
1270
1299
ep->d_type = newtype;
1272
1300
if (DOINGSOFTDEP(vdp)) {
1273
softdep_change_linkcnt(oip);
1274
1301
softdep_setup_directory_change(bp, dp, oip, newinum, isrmdir);
1278
DIP_SET(oip, i_nlink, oip->i_nlink);
1279
oip->i_flag |= IN_CHANGE;
1280
1304
if (DOINGASYNC(vdp)) {
1316
1338
struct dirtemplate dbuf;
1317
1339
struct direct *dp = (struct direct *)&dbuf;
1318
int error, count, namlen;
1319
1342
#define MINDIRSIZ (sizeof (struct dirtemplate) / 2)
1321
1344
for (off = 0; off < ip->i_size; off += dp->d_reclen) {
1365
ufs_dir_dd_ino(struct vnode *vp, struct ucred *cred, ino_t *dd_ino)
1388
ufs_dir_dd_ino(struct vnode *vp, struct ucred *cred, ino_t *dd_ino,
1389
struct vnode **dd_vp)
1367
1391
struct dirtemplate dirbuf;
1368
1393
int error, namlen;
1395
ASSERT_VOP_LOCKED(vp, "ufs_dir_dd_ino");
1370
1396
if (vp->v_type != VDIR)
1371
1397
return (ENOTDIR);
1399
* First check to see if we have it in the name cache.
1401
if ((ddvp = vn_dir_dd_ino(vp)) != NULL) {
1402
KASSERT(ddvp->v_mount == vp->v_mount,
1403
("ufs_dir_dd_ino: Unexpected mount point crossing"));
1404
*dd_ino = VTOI(ddvp)->i_number;
1409
* Have to read the directory.
1372
1411
error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,
1373
1412
sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE,
1374
1413
IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, NULL, NULL);
1386
1425
dirbuf.dotdot_name[1] != '.')
1387
1426
return (ENOTDIR);
1388
1427
*dd_ino = dirbuf.dotdot_ino;
1393
1433
* Check if source directory is in the path of the target directory.
1394
* Target is supplied locked, source is unlocked.
1395
* The target is always vput before returning.
1398
ufs_checkpath(ino_t source_ino, struct inode *target, struct ucred *cred)
1436
ufs_checkpath(ino_t source_ino, ino_t parent_ino, struct inode *target, struct ucred *cred, ino_t *wait_ino)
1400
struct vnode *vp, *vp1;
1439
struct vnode *tvp, *vp, *vp1;
1405
if (target->i_number == source_ino) {
1443
vp = tvp = ITOV(target);
1446
if (target->i_number == source_ino)
1448
if (target->i_number == parent_ino)
1410
1450
if (target->i_number == ROOTINO)
1414
error = ufs_dir_dd_ino(vp, cred, &dd_ino);
1453
error = ufs_dir_dd_ino(vp, cred, &dd_ino, &vp1);
1415
1454
if (error != 0)
1417
1456
if (dd_ino == source_ino) {
1421
1460
if (dd_ino == ROOTINO)
1423
error = vn_vget_ino(vp, dd_ino, LK_EXCLUSIVE, &vp1);
1426
/* Recheck that ".." still points to vp1 after relock of vp */
1427
error = ufs_dir_dd_ino(vp, cred, &dd_ino);
1432
/* Redo the check of ".." if directory was reparented */
1433
if (dd_ino != VTOI(vp1)->i_number) {
1462
if (dd_ino == parent_ino)
1465
error = VFS_VGET(mp, dd_ino, LK_SHARED | LK_NOWAIT,
1472
KASSERT(dd_ino == VTOI(vp1)->i_number,
1473
("directory %d reparented\n", VTOI(vp1)->i_number));
1442
1479
if (error == ENOTDIR)
1443
printf("checkpath: .. not a directory\n");
1480
panic("checkpath: .. not a directory\n");
1446
1485
return (error);