~ubuntu-branches/debian/jessie/ufsutils/jessie

« back to all changes in this revision

Viewing changes to sys/ufs/ufs/ufs_lookup.c

  • Committer: Package Import Robot
  • Author(s): Robert Millan
  • Date: 2013-11-29 14:21:12 UTC
  • mfrom: (11.1.1 experimental)
  • Revision ID: package-import@ubuntu.com-20131129142112-5tz5g7a4b6prb0dt
Tags: 9.2-2
* Avoid kfreebsd-kernel-headers versions prior to ino_t fix.
* Remove gratuitous dependency on libtermcap / libtinfo.

Show diffs side-by-side

added added

removed removed

Lines of Context:
37
37
#include <sys/cdefs.h>
38
38
__FBSDID("$FreeBSD$");
39
39
 
40
 
#include "opt_ffs_broken_fixme.h"
41
40
#include "opt_ufs.h"
42
41
#include "opt_quota.h"
43
42
 
77
76
/* true if old FS format...*/
78
77
#define OFSFMT(vp)      ((vp)->v_mount->mnt_maxsymlinklen <= 0)
79
78
 
80
 
static int ufs_lookup_(struct vnode *, struct vnode **, struct componentname *,
81
 
    ino_t *);
82
 
 
83
79
#ifdef QUOTA
84
80
static int
85
81
ufs_lookup_upgrade_lock(struct vnode *vp)
215
211
        } */ *ap;
216
212
{
217
213
 
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));
219
215
}
220
216
 
221
 
static int
222
 
ufs_lookup_(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp,
 
217
int
 
218
ufs_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp,
223
219
    ino_t *dd_ino)
224
220
{
225
221
        struct inode *dp;               /* inode for directory being searched */
251
247
                *vpp = NULL;
252
248
 
253
249
        dp = VTOI(vdp);
 
250
        if (dp->i_effnlink == 0)
 
251
                return (ENOENT);
254
252
 
255
253
        /*
256
254
         * Create a vm object if vmiodirenable is enabled.
557
555
        return (ENOENT);
558
556
 
559
557
found:
 
558
        if (dd_ino != NULL)
 
559
                *dd_ino = ino;
560
560
        if (numdirpasses == 2)
561
561
                nchstats.ncs_pass2++;
562
562
        /*
579
579
        if ((flags & ISLASTCN) && nameiop == LOOKUP)
580
580
                dp->i_diroff = i_offset &~ (DIRBLKSIZ - 1);
581
581
 
582
 
        if (dd_ino != NULL) {
583
 
                *dd_ino = ino;
584
 
                return (0);
585
 
        }
586
 
 
587
582
        /*
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)
596
 
                        return (error);
597
 
 
598
 
                error = ufs_delete_denied(vdp, tdp, cred, cnp->cn_thread);
599
 
                if (error) {
600
 
                        vput(tdp);
601
 
                        return (error);
602
 
                }
603
 
 
604
 
 
605
589
                /*
606
590
                 * Return pointer to current entry in dp->i_offset,
607
591
                 * and distance past previous entry (if there
618
602
                        dp->i_count = 0;
619
603
                else
620
604
                        dp->i_count = dp->i_offset - prevoff;
 
605
                if (dd_ino != NULL)
 
606
                        return (0);
 
607
                if ((error = VFS_VGET(vdp->v_mount, ino,
 
608
                    LK_EXCLUSIVE, &tdp)) != 0)
 
609
                        return (error);
 
610
                error = ufs_delete_denied(vdp, tdp, cred, cnp->cn_thread);
 
611
                if (error) {
 
612
                        vput(tdp);
 
613
                        return (error);
 
614
                }
621
615
                if (dp->i_number == ino) {
622
616
                        VREF(vdp);
623
617
                        *vpp = vdp;
649
643
                dp->i_offset = i_offset;
650
644
                if (dp->i_number == ino)
651
645
                        return (EISDIR);
 
646
                if (dd_ino != NULL)
 
647
                        return (0);
652
648
                if ((error = VFS_VGET(vdp->v_mount, ino,
653
649
                    LK_EXCLUSIVE, &tdp)) != 0)
654
650
                        return (error);
683
679
                cnp->cn_flags |= SAVENAME;
684
680
                return (0);
685
681
        }
 
682
        if (dd_ino != NULL)
 
683
                return (0);
686
684
 
687
685
        /*
688
686
         * Step through the translation in the name.  We do not `vput' the
714
712
                 * to the inode we looked up before vdp lock was
715
713
                 * dropped.
716
714
                 */
717
 
                error = ufs_lookup_(pdp, NULL, cnp, &ino1);
 
715
                error = ufs_lookup_ino(pdp, NULL, cnp, &ino1);
718
716
                if (error) {
719
717
                        vput(tdp);
720
718
                        return (error);
866
864
 * soft dependency code).
867
865
 */
868
866
int
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;
 
873
        int isrename;
875
874
{
876
875
        struct ucred *cr;
877
876
        struct thread *td;
944
943
                                blkoff += DIRBLKSIZ;
945
944
                        }
946
945
                        if (softdep_setup_directory_add(bp, dp, dp->i_offset,
947
 
                            dirp->d_ino, newdirbp, 1) == 0) {
948
 
                                bdwrite(bp);
 
946
                            dirp->d_ino, newdirbp, 1))
 
947
                                dp->i_flag |= IN_NEEDSYNC;
 
948
                        if (newdirbp)
 
949
                                bdwrite(newdirbp);
 
950
                        bdwrite(bp);
 
951
                        if ((dp->i_flag & IN_NEEDSYNC) == 0)
949
952
                                return (UFS_UPDATE(dvp, 0));
950
 
                        }
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.
 
953
                        /*
 
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.
 
961
                         *
 
962
                         * This synchronous step could be removed if fsck and
 
963
                         * the kernel were taught to fill in sparse
 
964
                         * directories rather than panic.
960
965
                         */
961
 
                        if ((error = bwrite(bp)))
962
 
                                return (error);
 
966
                        if (isrename)
 
967
                                return (0);
963
968
                        if (tvp != NULL)
964
969
                                VOP_UNLOCK(tvp, 0);
965
 
                        error = VOP_FSYNC(dvp, MNT_WAIT, td);
 
970
                        (void) VOP_FSYNC(dvp, MNT_WAIT, td);
966
971
                        if (tvp != NULL)
967
972
                                vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
968
973
                        return (error);
1048
1053
                            dp->i_offset + ((char *)ep - dirbuf));
1049
1054
#endif
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); 
1053
1058
                else
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)
 
1109
                        bdwrite(newdirbp);
1103
1110
                bdwrite(bp);
1104
1111
        } else {
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.
1119
1126
         */
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
1158
1166
 
1159
1167
        dp = VTOI(dvp);
1160
1168
 
 
1169
        /*
 
1170
         * Adjust the link count early so softdep can block if necessary.
 
1171
         */
 
1172
        if (ip) {
 
1173
                ip->i_effnlink--;
 
1174
                if (DOINGSOFTDEP(dvp)) {
 
1175
                        softdep_setup_unlink(dp, ip);
 
1176
                } else {
 
1177
                        ip->i_nlink--;
 
1178
                        DIP_SET(ip, i_nlink, ip->i_nlink);
 
1179
                        ip->i_flag |= IN_CHANGE;
 
1180
                }
 
1181
        }
1161
1182
        if (flags & DOWHITEOUT) {
1162
1183
                /*
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);
1189
1210
#endif
 
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) {
1191
1215
                /*
1192
1216
                 * First entry in block: set d_ino to zero.
1205
1229
                    dp->i_offset & ~(DIRBLKSIZ - 1));
1206
1230
#endif
1207
1231
out:
 
1232
        error = 0;
1208
1233
        if (DOINGSOFTDEP(dvp)) {
1209
 
                if (ip) {
1210
 
                        ip->i_effnlink--;
1211
 
                        softdep_change_linkcnt(ip);
 
1234
                if (ip)
1212
1235
                        softdep_setup_remove(bp, dp, ip, isrmdir);
1213
 
                }
1214
 
                if (softdep_slowdown(dvp)) {
 
1236
                if (softdep_slowdown(dvp))
1215
1237
                        error = bwrite(bp);
1216
 
                } else {
 
1238
                else
1217
1239
                        bdwrite(bp);
1218
 
                        error = 0;
1219
 
                }
1220
1240
        } else {
1221
 
                if (ip) {
1222
 
                        ip->i_effnlink--;
1223
 
                        ip->i_nlink--;
1224
 
                        DIP_SET(ip, i_nlink, ip->i_nlink);
1225
 
                        ip->i_flag |= IN_CHANGE;
1226
 
                }
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)
1230
1244
                        bdwrite(bp);
1231
 
                        error = 0;
1232
 
                } else
 
1245
                else
1233
1246
                        error = bwrite(bp);
1234
1247
        }
1235
1248
        dp->i_flag |= IN_CHANGE | IN_UPDATE;
1238
1251
         * drop its snapshot reference so that it will be reclaimed
1239
1252
         * when last open reference goes away.
1240
1253
         */
1241
 
#if defined(FFS) || defined(IFS)
1242
1254
        if (ip != 0 && (ip->i_flags & SF_SNAPSHOT) != 0 && ip->i_effnlink == 0)
1243
 
                ffs_snapgone(ip);
1244
 
#endif
 
1255
                UFS_SNAPGONE(ip);
1245
1256
        return (error);
1246
1257
}
1247
1258
 
1262
1273
        struct vnode *vdp = ITOV(dp);
1263
1274
        int error;
1264
1275
 
 
1276
        /*
 
1277
         * Drop the link before we lock the buf so softdep can block if
 
1278
         * necessary.
 
1279
         */
 
1280
        oip->i_effnlink--;
 
1281
        if (DOINGSOFTDEP(vdp)) {
 
1282
                softdep_setup_unlink(dp, oip);
 
1283
        } else {
 
1284
                oip->i_nlink--;
 
1285
                DIP_SET(oip, i_nlink, oip->i_nlink);
 
1286
                oip->i_flag |= IN_CHANGE;
 
1287
        }
 
1288
 
1265
1289
        error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp);
1266
1290
        if (error)
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) {
 
1294
                brelse(bp);
 
1295
                return (EIDRM);
 
1296
        }
1268
1297
        ep->d_ino = newinum;
1269
1298
        if (!OFSFMT(vdp))
1270
1299
                ep->d_type = newtype;
1271
 
        oip->i_effnlink--;
1272
1300
        if (DOINGSOFTDEP(vdp)) {
1273
 
                softdep_change_linkcnt(oip);
1274
1301
                softdep_setup_directory_change(bp, dp, oip, newinum, isrmdir);
1275
1302
                bdwrite(bp);
1276
1303
        } else {
1277
 
                oip->i_nlink--;
1278
 
                DIP_SET(oip, i_nlink, oip->i_nlink);
1279
 
                oip->i_flag |= IN_CHANGE;
1280
1304
                if (DOINGASYNC(vdp)) {
1281
1305
                        bdwrite(bp);
1282
1306
                        error = 0;
1290
1314
         * drop its snapshot reference so that it will be reclaimed
1291
1315
         * when last open reference goes away.
1292
1316
         */
1293
 
#if defined(FFS) || defined(IFS)
1294
1317
        if ((oip->i_flags & SF_SNAPSHOT) != 0 && oip->i_effnlink == 0)
1295
 
                ffs_snapgone(oip);
1296
 
#endif
 
1318
                UFS_SNAPGONE(oip);
1297
1319
        return (error);
1298
1320
}
1299
1321
 
1315
1337
        doff_t off;
1316
1338
        struct dirtemplate dbuf;
1317
1339
        struct direct *dp = (struct direct *)&dbuf;
1318
 
        int error, count, namlen;
 
1340
        int error, namlen;
 
1341
        ssize_t count;
1319
1342
#define MINDIRSIZ (sizeof (struct dirtemplate) / 2)
1320
1343
 
1321
1344
        for (off = 0; off < ip->i_size; off += dp->d_reclen) {
1362
1385
}
1363
1386
 
1364
1387
static int
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)
1366
1390
{
1367
1391
        struct dirtemplate dirbuf;
 
1392
        struct vnode *ddvp;
1368
1393
        int error, namlen;
1369
1394
 
 
1395
        ASSERT_VOP_LOCKED(vp, "ufs_dir_dd_ino");
1370
1396
        if (vp->v_type != VDIR)
1371
1397
                return (ENOTDIR);
 
1398
        /*
 
1399
         * First check to see if we have it in the name cache.
 
1400
         */
 
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;
 
1405
                *dd_vp = ddvp;
 
1406
                return (0);
 
1407
        }
 
1408
        /*
 
1409
         * Have to read the directory.
 
1410
         */
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;
 
1428
        *dd_vp = NULL;
1389
1429
        return (0);
1390
1430
}
1391
1431
 
1392
1432
/*
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.
1396
1434
 */
1397
1435
int
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)
1399
1437
{
1400
 
        struct vnode *vp, *vp1;
 
1438
        struct mount *mp;
 
1439
        struct vnode *tvp, *vp, *vp1;
1401
1440
        int error;
1402
1441
        ino_t dd_ino;
1403
1442
 
1404
 
        vp = ITOV(target);
1405
 
        if (target->i_number == source_ino) {
1406
 
                error = EEXIST;
1407
 
                goto out;
1408
 
        }
1409
 
        error = 0;
 
1443
        vp = tvp = ITOV(target);
 
1444
        mp = vp->v_mount;
 
1445
        *wait_ino = 0;
 
1446
        if (target->i_number == source_ino)
 
1447
                return (EEXIST);
 
1448
        if (target->i_number == parent_ino)
 
1449
                return (0);
1410
1450
        if (target->i_number == ROOTINO)
1411
 
                goto out;
1412
 
 
 
1451
                return (0);
1413
1452
        for (;;) {
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)
1416
1455
                        break;
1417
1456
                if (dd_ino == source_ino) {
1420
1459
                }
1421
1460
                if (dd_ino == ROOTINO)
1422
1461
                        break;
1423
 
                error = vn_vget_ino(vp, dd_ino, LK_EXCLUSIVE, &vp1);
1424
 
                if (error != 0)
1425
 
                        break;
1426
 
                /* Recheck that ".." still points to vp1 after relock of vp */
1427
 
                error = ufs_dir_dd_ino(vp, cred, &dd_ino);
1428
 
                if (error != 0) {
1429
 
                        vput(vp1);
1430
 
                        break;
1431
 
                }
1432
 
                /* Redo the check of ".." if directory was reparented */
1433
 
                if (dd_ino != VTOI(vp1)->i_number) {
1434
 
                        vput(vp1);
1435
 
                        continue;
1436
 
                }
1437
 
                vput(vp);
 
1462
                if (dd_ino == parent_ino)
 
1463
                        break;
 
1464
                if (vp1 == NULL) {
 
1465
                        error = VFS_VGET(mp, dd_ino, LK_SHARED | LK_NOWAIT,
 
1466
                            &vp1);
 
1467
                        if (error != 0) {
 
1468
                                *wait_ino = dd_ino;
 
1469
                                break;
 
1470
                        }
 
1471
                }
 
1472
                KASSERT(dd_ino == VTOI(vp1)->i_number,
 
1473
                    ("directory %d reparented\n", VTOI(vp1)->i_number));
 
1474
                if (vp != tvp)
 
1475
                        vput(vp);
1438
1476
                vp = vp1;
1439
1477
        }
1440
1478
 
1441
 
out:
1442
1479
        if (error == ENOTDIR)
1443
 
                printf("checkpath: .. not a directory\n");
1444
 
        if (vp != NULL)
 
1480
                panic("checkpath: .. not a directory\n");
 
1481
        if (vp1 != NULL)
 
1482
                vput(vp1);
 
1483
        if (vp != tvp)
1445
1484
                vput(vp);
1446
1485
        return (error);
1447
1486
}