[comp.unix.wizards] Reserving Space on Disk

markd@silogic.UUCP (Mark DiVecchio) (07/10/90)

An associate has an application where he wants to reserve 4Mb of disk
space.  The unix file system does not support this since opening the
file, seeking to 4Mb and writing one byte does not do the trick. 
Besides writing out 4Mb of filler, is there any other way to do this?
-- 
Mark DiVecchio, Silogic Systems, 619-549-9841                       K3FWT
-----   9888 Carroll Center Road, Suite 113, San Diego, CA 92126    -----
markd@silogic                                  BBS 619-549-3927
...!ucsd!celerity!celit!silogic!markd     celerity!silogic!markd@ucsd.edu

istvan@hhb.UUCP (Istvan Mohos) (07/15/90)

markd@silogic.UUCP (Mark DiVecchio @ Silogic Systems) writes:
>An associate has an application where he wants to reserve 4Mb of disk
>space.  The unix file system does not support this since opening the
>file, seeking to 4Mb and writing one byte does not do the trick. 
>Besides writing out 4Mb of filler, is there any other way to do this?

Because disk I/O optimizations are kernel tasks, there is very little
you can do unless you're willing to rewrite the buffer cache routines,
forcing the system to pop a few free blocks and reassign them to your
inode.  (Consult Chap. 3 of "The Design Of The UNIX Operating System"
by Maurice J. Bach for details.)

Personally, I can't blame a philosophy of having to actually write to
the disk if one wants to take up space on it; in spite that

    if (write (fd, malloc(FOURMEG), FOURMEG) != FOURMEG)
        perror("malloc or write error"), exit (1);

does take a few seconds to execute, "delayed-write" or not.  Maybe
you should just fork off this task and go on to something else.

-- 
        Istvan Mohos
        ...uunet!pyrdc!pyrnj!hhb!istvan
        RACAL-REDAC/HHB 1000 Wyckoff Ave. Mahwah NJ 07430 201-848-8000
======================================================================

cpcahil@virtech.uucp (Conor P. Cahill) (07/16/90)

In article <563@hhb.UUCP> istvan@hhb.UUCP (Istvan Mohos) writes:
>    if (write (fd, malloc(FOURMEG), FOURMEG) != FOURMEG)
>        perror("malloc or write error"), exit (1);

While I know this is just an example & is not intended to be a 
suggestion of what to do, I just have to comment on it to ensure 
that some impressionable engineer doesn't think this is a 
good thing to do.

Anyway, my comment is never (not even in an example (unless it is
an example of what not to do)) ever use the return of any function
that may return NULL before you check it to see if it returned NULL.

Your perror() seems to indicated that if the malloc had failed, the write
would return -1 and set errno accordingly.  In fact, the malloc failure
would return a NULL pointer and then write would try to write out 4MB
from that location.  On most machines this would result in a
core dump, either because NULL was not a valid address, or because
there was not 4MB in the user's address space following that 
pointer.

I'm not harping on you.  I just feel that I must emphasize this
point.  Too often I see code that does something like the above, 
although getenv() is more often the culprit.


-- 
Conor P. Cahill            (703)430-9247        Virtual Technologies, Inc.,
uunet!virtech!cpcahil                           46030 Manekin Plaza, Suite 160
                                                Sterling, VA 22170 

moss@cs.umass.edu (Eliot Moss) (07/16/90)

I don't think tromping through 4 megabytes of newly allocated address space
will be much of a winner myself. I'd do something more along these lines
(error checking omitted):

char buf[ONE_K];
int i;

for (i = 0; i < FOUR_K; ++i)
  write (fd, buf, ONE_K);

You might want to tune the size of buf up larger than what I have, but still
somewhat "reasonable". Something between the size of a track and a cylinder on
the disk might work reasonably well, say 64K or 128K. Enjoy!		Eliot
--

		J. Eliot B. Moss, Assistant Professor
		Department of Computer and Information Science
		Lederle Graduate Research Center
		University of Massachusetts
		Amherst, MA  01003
		(413) 545-4206; Moss@cs.umass.edu

jik@athena.mit.edu (Jonathan I. Kamens) (07/16/90)

In article <MOSS.90Jul15190502@ibis.cs.umass.edu>, moss@cs.umass.edu
(Eliot Moss) writes:
|> char buf[ONE_K];
|> int i;
|> 
|> for (i = 0; i < FOUR_K; ++i)
|>   write (fd, buf, ONE_K);

  I wrote the short program below (which I call "fillspace") when I was
testing some bug fixes for bugs that would exhibit themselves only when
a disk partition was almost full.  I needed to be able to fill a
specific amount of disk space in order to get into that situation easily.

  I've found it useful in other situations as well.  How to use it is
fairly obvious from the usage message in the code.

Jonathan Kamens			              USnail:
MIT Project Athena				11 Ashford Terrace
jik@Athena.MIT.EDU				Allston, MA  02134
Office: 617-253-8495			      Home: 617-782-0710

------------------------------------------------------------------

#include <stdio.h>

extern char *malloc();

main(argc, argv)
int argc;
char *argv[];
{
     int k;
     char *garbage;
     int blocksize;
     int block;
     int i;
     
     if (argc < 2 || argc > 3) {
	  fprintf(stderr, "Usage: %s blocks [blocksize]\n", argv[0]);
	  exit(1);
     }

     if (argc == 3)
	  blocksize = atoi(argv[2]);
     else
	  blocksize = BUFSIZ;

     k = atoi(argv[1]) * blocksize;

     if (k <= 0 || blocksize <= 0) {
	  fprintf(stderr, "%s: blocks and blocksize must be positive\n",
		  argv[0]);
	  exit(1);
     }
     
     block = 4 * blocksize;
     garbage = malloc((unsigned) block);
     if (! garbage) {
	  perror("malloc");
	  exit(1);
     }

     for (i = 0; i < block; i++)
	  garbage[i] = 'a';

     while (k) {
	  while (k >= block) {
	       fwrite(garbage, 1, block, stdout);
	       k -= block;
	  }
	  block /= 2;
     }

     exit(0);
}

cjc@ulysses.att.com (Chris Calabrese[mav]) (07/16/90)

In article <MOSS.90Jul15190502@ibis.cs.umass.edu>, moss@cs.umass.edu (Eliot Moss) writes:
> [ ... ]
> 
> char buf[ONE_K];
> int i;
> 
> for (i = 0; i < FOUR_K; ++i)
>   write (fd, buf, ONE_K);
> [ ... ]

BTW, while reading the various ways to write some large space on the
disk which have been passing by, I thought I'd pass a related tidbit
along.  On many machine architectures, byte copying from user space to
kernel space is quite a bit faster if the buffer is word aligned.

For this reason, it is better to use malloc to get your buffer than to
allocate it off of the stack (as malloc always returns maximally
aligned memory).  Of course, this assumes that you'll use the buffer
more than once, as the time to malloc() is around the same order as
the time to deal with the non-aligned bytes at the beginning and end
of the buffer.
Name:			Christopher J. Calabrese
Brain loaned to:	AT&T Bell Laboratories, Murray Hill, NJ
att!ulysses!cjc		cjc@ulysses.att.com
Obligatory Quote:	``pher - gr. vb. to schlep.  phospher - to schlep light.philosopher - to schlep thoughts.''

martin@mwtech.UUCP (Martin Weitzel) (07/17/90)

In article <13422@ulysses.att.com> cjc@ulysses.att.com (Chris Calabrese[mav]) writes:
:In article <MOSS.90Jul15190502@ibis.cs.umass.edu>, moss@cs.umass.edu (Eliot Moss) writes:
:> [ ... ]
:> 
:> char buf[ONE_K];
:> int i;
:> 
:> for (i = 0; i < FOUR_K; ++i)
:>   write (fd, buf, ONE_K);
:> [ ... ]
:
:BTW, while reading the various ways to write some large space on the
:disk which have been passing by, I thought I'd pass a related tidbit
:along.  On many machine architectures, byte copying from user space to
:kernel space is quite a bit faster if the buffer is word aligned.
:
:For this reason, it is better to use malloc to get your buffer than to
:allocate it off of the stack (as malloc always returns maximally
:aligned memory).  Of course, this assumes that you'll use the buffer
:more than once, as the time to malloc() is around the same order as
:the time to deal with the non-aligned bytes at the beginning and end
:of the buffer.

What is wrong with the following approach (at least on non-BSD-ish
file systems)?

	while file has not desired size
		lseek(2) from current position forward
		disk-block-size bytes minus 1 and write(2)
		one byte

IMHO this should fill the disk and avoids much copying from user-space.
-- 
Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83

fnf@riscokid.UUCP (Fred Fish) (07/17/90)

In article <MOSS.90Jul15190502@ibis.cs.umass.edu> moss@cs.umass.edu writes:
>char buf[ONE_K];
>int i;
>
>for (i = 0; i < FOUR_K; ++i)
>  write (fd, buf, ONE_K);
>
>You might want to tune the size of buf up larger than what I have, but still
>somewhat "reasonable". Something between the size of a track and a cylinder on
>the disk might work reasonably well, say 64K or 128K. Enjoy!		Eliot

This reminds me, I've always wondered why there wasn't a /dev/full as a
standard part of unix.  It's the obvious counterpart of /dev/null, and
simply returns as many null bytes as you ask for.  Then all you would
have to do is:

	dd if=/dev/full of=myfile bs=1k count=4k

-Fred

ag@cbmvax.commodore.com (Keith Gabryelski) (07/17/90)

In article <13212@mcdphx.phx.mcd.mot.com> fnf@riscokid.UUCP (Fred Fish) writes:
>[...], I've always wondered why there wasn't a /dev/full as a
>standard part of unix.  It's the obvious counterpart of /dev/null, and
>simply returns as many null bytes as you ask for.  Then all you would
>have to do is:
>
>	dd if=/dev/full of=myfile bs=1k count=4k

On some of the latest forms of Unix (SVR4 which inherited it from
SunOS) there is a /dev/zero which does this.  It is used for mmap()ing
in the bss segment and ignoring null pointer problems :-).

Pax, Keith

stripes@eng.umd.edu (Joshua Osborne) (07/17/90)

In article <13212@mcdphx.phx.mcd.mot.com> fnf@riscokid.UUCP (Fred Fish) writes:
>This reminds me, I've always wondered why there wasn't a /dev/full as a
>standard part of unix.  It's the obvious counterpart of /dev/null, and
>simply returns as many null bytes as you ask for.  Then all you would
>have to do is:
>
>	dd if=/dev/full of=myfile bs=1k count=4k
SunOS has a /dev/zero, it does exactly what you want.  They use it to get
zero mapped pages (ld.so mmap()s shared lib's data space from the /dev/zero
file).
-- 
           stripes@eng.umd.edu          "Security for Unix is like
      Josh_Osborne@Real_World,The          Mutitasking for MS-DOS"
      "The dyslexic porgramer"                  - Kevin Lockwood
"Don't try to change C into some nice, safe, portable programming language
 with all sharp edges removed, pick another language."  - John Limpert

stripes@eng.umd.edu (Joshua Osborne) (07/17/90)

In article <836@mwtech.UUCP> martin@mwtech.UUCP (Martin Weitzel) writes:
>In article <13422@ulysses.att.com> cjc@ulysses.att.com (Chris Calabrese[mav]) writes:
>:For this reason, it is better to use malloc to get your buffer than to
>:allocate it off of the stack (as malloc always returns maximally
>:aligned memory).  Of course, this assumes that you'll use the buffer
>:more than once, as the time to malloc() is around the same order as
>:the time to deal with the non-aligned bytes at the beginning and end
>:of the buffer.

>What is wrong with the following approach (at least on non-BSD-ish
>file systems)?
>
>	while file has not desired size
>		lseek(2) from current position forward
>		disk-block-size bytes minus 1 and write(2)
>		one byte
>
>IMHO this should fill the disk and avoids much copying from user-space.

That may cause alot less copying from user-space, but it causes more context
switches from user to kernel & back.  Mabie someone wants to try their hand
at writev()?  I think you can get writev to seek before each write.
Alternetly how about mmap?  You can mmap a half a meg at a time, that ought
to reduce the number of syscalls, only write once every 8K (or whatever
the disk block size is) reducing the memmory bandwidth, but will this result
in fewer context switches then write?  Then writev?
-- 
           stripes@eng.umd.edu          "Security for Unix is like
      Josh_Osborne@Real_World,The          Mutitasking for MS-DOS"
      "The dyslexic porgramer"                  - Kevin Lockwood
"Don't try to change C into some nice, safe, portable programming language
 with all sharp edges removed, pick another language."  - John Limpert

lerman@stpstn.UUCP (Ken Lerman) (07/17/90)

In article <836@mwtech.UUCP> martin@mwtech.UUCP (Martin Weitzel) writes:
>In article <13422@ulysses.att.com> cjc@ulysses.att.com (Chris Calabrese[mav]) writes:
[... much deleted ...]
>What is wrong with the following approach (at least on non-BSD-ish
>file systems)?
>
>	while file has not desired size
>		lseek(2) from current position forward
>		disk-block-size bytes minus 1 and write(2)
>		one byte
>
>IMHO this should fill the disk and avoids much copying from user-space.
>-- 
>Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83

But if you wrote two bytes at a time, you could write the last byte of
one block and the first byte of the next in one write.

That would seem to be an advantage.

But only the wizards know for sure, and I probably don't qualify in
this forum.

Ken

moss@cs.umass.edu (Eliot Moss) (07/17/90)

The real problem with writing a few bytes here and there is that it probably
leaves holes in the file -- i.e., the space is not really allocated. Copying
from /dev/zero might give the same problem (blocks of all zeroes not being
stored). The person needed actual disk blocks allocated so that writes could
proceed very quickly and not need to go through any block allocation.
--

		J. Eliot B. Moss, Assistant Professor
		Department of Computer and Information Science
		Lederle Graduate Research Center
		University of Massachusetts
		Amherst, MA  01003
		(413) 545-4206; Moss@cs.umass.edu

istvan@hhb.UUCP (Istvan Mohos) (07/18/90)

cpcahil@virtech.uucp (Conor P. Cahill) writes:
:istvan@hhb.UUCP (Istvan Mohos) writes:
:>    if (write (fd, malloc(FOURMEG), FOURMEG) != FOURMEG)
:>        perror("malloc or write error"), exit (1);
:
:While I know this is just an example & is not intended to be a 
:suggestion of what to do, I just have to comment on it to ensure 
:that some impressionable engineer doesn't think this is a 
:good thing to do.

The original question from markd@silogic.UUCP (Mark DiVecchio)
produced no net responses for a week; just thought I'd stick a
twig of controversy into the flames and watch the sparks fly :-)

-- 
        Istvan Mohos
        ...uunet!pyrdc!pyrnj!hhb!istvan
        RACAL-REDAC/HHB 1000 Wyckoff Ave. Mahwah NJ 07430 201-848-8000
======================================================================

istvan@hhb.UUCP (Istvan Mohos) (07/18/90)

martin@mwtech.UUCP (Martin Weitzel) writes:
>What is wrong with the following approach (at least on non-BSD-ish
>file systems)?
>
>	while file has not desired size
>		lseek(2) from current position forward
>		disk-block-size bytes minus 1 and write(2)
>		one byte
>
>IMHO this should fill the disk and avoids much copying from user-space.

This, and the majority of the responses, focus on the merits of byte
copying.  The real issue is the lack of speed in physically accessing
the disk.  The program segments posted by others, or your algorithm
converted to C (with impending corrections from Conor P. Cahill :-)

#include <stdio.h>
#include <sys/file.h>
#define FOURMEG 4194304
#define DBLK    512
#define ITER    (FOURMEG/DBLK)
main()
{
    long lseek();
    char c = 0;
    register int fd, ri;

	if ((fd = open("foo", O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1)
		perror("can't write to"), exit (1);
    for (ri = ITER; --ri >= 0; write (fd, &c, 1))
        if (lseek (fd, (long)DBLK-1, 1) == -1)
    		perror("seek error"), exit (2);
    exit (0);
}

are all slower then writing 4 Meg in one disk access.
-- 
        Istvan Mohos
        ...uunet!pyrdc!pyrnj!hhb!istvan
        RACAL-REDAC/HHB 1000 Wyckoff Ave. Mahwah NJ 07430 201-848-8000
======================================================================

I.G.Batten@fulcrum.bt.co.uk (Ian G Batten) (07/19/90)

Most articles on this subject seem to neglect the fact that many Unix
file-systems do not allocate blocks of all zeros.  Therefore lseeking
``a lot'' and writing one byte probably only allocates the block for the
byte you wrote.

ian

pd@ixi.uucp (Paul Davey) (07/23/90)

If you using SunOs, (and other systems supporting NFS booting) would
not mkfile(8) be suitable?

     mkfile creates one or more files that are suitable  for  use
     as  NFS-mounted  swap  areas,  or  as local swap areas.  The
     sticky bit is set, and the file is  padded  with  zeroes  by
     default.   The  default  size  is  in  bytes,  but it can be
     flagged as kilobytes, blocks, or megabytes, with the  k,  b,
     or m suffixes, respectively.

OK so it's meant for NFS swap, but its esentially a (contiguous?)
totally allocated file. I don't see that you couldn't use it for any
other purpose.

--
 Regards,			 pd@x.co.uk          IXI Limited
	Paul Davey		 pd@ixi.uucp         62-74 Burleigh St.
				 ...!uunet!ixi!pd    Cambridge  U.K.
 "These are interesting times"   +44 223 462 131     CB1  1OJ      

eliot@chutney.rtp.dg.com (Topher Eliot) (07/30/90)

|> Alternetly how about mmap?  You can mmap a half a meg at a time, that ought
|> to reduce the number of syscalls, only write once every 8K (or whatever
|> the disk block size is) reducing the memmory bandwidth, but will this result
|> in fewer context switches then write?  Then writev?

Well, it would avoid explicit context switches, but would undoubtedly involve
some non-trivial number of page faults.  Can anyone out there educate us on
how many page faults could be expected?

Topher Eliot
Data General Corporation                eliot@dg-rtp.dg.com
62 T. W. Alexander Drive                {backbone}!mcnc!rti!dg-rtp!eliot
Research Triangle Park, NC 27709        (919) 248-6371
Obviously, I speak for myself, not for DG.