* Copyright (c) 1982, 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
* @(#)ufs_disksubr.c 7.5 (Berkeley) %G%
* Seek sort for disks. We depend on the driver
* which calls us using b_resid as the current cylinder number.
* The argument dp structure holds a b_actf activity chain pointer
* on which we keep two queues, sorted in ascending cylinder order.
* The first queue holds those requests which are positioned after
* the current cylinder (in the first request); the second holds
* requests which came in after their cylinder number was passed.
* Thus we implement a one way scan, retracting after reaching the
* end of the drive to the first request on the second queue,
* at which time it becomes the first queue.
* A one-way scan is natural because of the way UNIX read-ahead
register struct buf
*dp
, *bp
;
* If nothing on the activity queue, then
* we become the only thing.
* If we lie after the first (currently active)
* request, then we must locate the second request list
* and add ourselves to it.
if (bp
->b_cylin
< ap
->b_cylin
) {
* Check for an ``inversion'' in the
* normally ascending cylinder numbers,
* indicating the start of the second request list.
if (ap
->av_forw
->b_cylin
< ap
->b_cylin
) {
* Search the second request list
* for the first request at a larger
* cylinder number. We go before that;
* if there is no such request, we go at end.
if (bp
->b_cylin
< ap
->av_forw
->b_cylin
)
if (bp
->b_cylin
== ap
->av_forw
->b_cylin
&&
bp
->b_blkno
< ap
->av_forw
->b_blkno
)
goto insert
; /* after last */
* No inversions... we will go after the last, and
* be the first request in the second request list.
* Request is at/after the current request...
* sort in the first request list.
* We want to go after the current request
* if there is an inversion after it (i.e. it is
* the end of the first request list), or if
* the next request is a larger cylinder than our request.
if (ap
->av_forw
->b_cylin
< ap
->b_cylin
||
bp
->b_cylin
< ap
->av_forw
->b_cylin
||
(bp
->b_cylin
== ap
->av_forw
->b_cylin
&&
bp
->b_blkno
< ap
->av_forw
->b_blkno
))
* Neither a second list nor a larger
* request... we go at the end of the first list,
* which is the same as the end of the whole schebang.
bp
->av_forw
= ap
->av_forw
;
* Attempt to read a disk label from a device
* using the indicated stategy routine.
* The label must be partly set up before this:
* secpercyl and anything required in the strategy routine
* (e.g., sector size) must be filled in before calling us.
* Returns null on success and an error string on failure.
readdisklabel(dev
, strat
, lp
)
register struct disklabel
*lp
;
if (lp
->d_secperunit
== 0)
lp
->d_secperunit
= 0x1fffffff;
if (lp
->d_partitions
[0].p_size
== 0)
lp
->d_partitions
[0].p_size
= 0x1fffffff;
lp
->d_partitions
[0].p_offset
= 0;
bp
= geteblk(lp
->d_secsize
);
bp
->b_blkno
= LABELSECTOR
;
bp
->b_bcount
= lp
->d_secsize
;
bp
->b_flags
= B_BUSY
| B_READ
;
bp
->b_cylin
= LABELSECTOR
/ lp
->d_secpercyl
;
if (bp
->b_flags
& B_ERROR
) {
} else for (dlp
= (struct disklabel
*)bp
->b_un
.b_addr
;
dlp
<= (struct disklabel
*)(bp
->b_un
.b_addr
+DEV_BSIZE
-sizeof(*dlp
));
dlp
= (struct disklabel
*)((char *)dlp
+ sizeof(long))) {
if (dlp
->d_magic
!= DISKMAGIC
|| dlp
->d_magic2
!= DISKMAGIC
) {
} else if (dkcksum(dlp
) != 0)
msg
= "disk label corrupted";
if (lp
->d_npartitions
> MAXPARTITIONS
)
lp
->d_npartitions
= MAXPARTITIONS
;
bp
->b_flags
= B_INVAL
| B_AGE
;
* Check new disk label for sensibility
setdisklabel(olp
, nlp
, openmask
)
register struct disklabel
*olp
, *nlp
;
register struct partition
*opp
, *npp
;
if (nlp
->d_magic
!= DISKMAGIC
|| nlp
->d_magic2
!= DISKMAGIC
||
while ((i
= ffs(openmask
)) != 0) {
if (nlp
->d_npartitions
<= i
)
opp
= &olp
->d_partitions
[i
];
npp
= &nlp
->d_partitions
[i
];
if (npp
->p_offset
!= opp
->p_offset
|| npp
->p_size
< opp
->p_size
)
* Copy internally-set partition information
* if new label doesn't include it. XXX
if (npp
->p_fstype
== FS_UNUSED
&& opp
->p_fstype
!= FS_UNUSED
) {
npp
->p_fstype
= opp
->p_fstype
;
npp
->p_fsize
= opp
->p_fsize
;
npp
->p_frag
= opp
->p_frag
;
/* encoding of disk minor numbers, should be elsewhere... */
#define dkunit(dev) (minor(dev) >> 3)
#define dkpart(dev) (minor(dev) & 07)
#define dkminor(unit, part) (((unit) << 3) | (part))
* Write disk label back to device after modification.
writedisklabel(dev
, strat
, lp
)
register struct disklabel
*lp
;
if (lp
->d_partitions
[labelpart
].p_offset
!= 0) {
if (lp
->d_partitions
[0].p_offset
!= 0)
return (EXDEV
); /* not quite right */
bp
= geteblk(lp
->d_secsize
);
bp
->b_dev
= makedev(major(dev
), dkminor(dkunit(dev
), labelpart
));
bp
->b_blkno
= LABELSECTOR
;
bp
->b_bcount
= lp
->d_secsize
;
if (bp
->b_flags
& B_ERROR
) {
error
= u
.u_error
; /* XXX */
dlp
= (struct disklabel
*)(bp
->b_un
.b_addr
+ LABELOFFSET
);
(*strat
)(bp
); biowait(bp
);
if (bp
->b_flags
& B_ERROR
) {
error
= u
.u_error
; /* XXX */
* Compute checksum for disk label.
register struct disklabel
*lp
;
register u_short
*start
, *end
;
register u_short sum
= 0;
end
= (u_short
*)&lp
->d_partitions
[lp
->d_npartitions
];