PDA

View Full Version : Series2 IDE ioctl support in vplay / mfs_*



alldeadhomiez
05-18-2004, 03:36 PM
Both Series 1 and Series 2 TiVos provide a kernel facility that provides direct, uncached disk I/O, intended for transferring bulk stream data quickly and with low overhead. On S1 2.1.x kernels, it was provided in the form of two new syscalls: readsectors and writesectors. On S2 2.4.x kernels, it is provided in the form of a new ioctl, HDIO_DRIVE_TIVO_IO, which takes pretty much the same parameters but uses a different struct to pass them.

As far as I could tell, nobody has posted vplay sources that support the S2 ioctls, so I am posting my modified util.c here. Preliminary tests have shown big speed improvements with myworld not running, and less impressive results on a loaded system. Either way, bypassing the Linux buffer cache when dealing with streams is a huge plus, as read()/write() wastes valuable memory and cycles shifting around ephemeral data.

I have not tried it yet but it is possible that performance could be further improved by page-aligning the I/O buffers, and eliminating the double buffering in mfs_ftp by passing the socket's file descriptor when possible.

gorilla daddy
09-12-2004, 07:56 PM
Sending a block of data takes time, so does reading it off the disk. This export_file() replacement forks off the send of a 1MB block, and while sending, reads the next block. The result is a continuous stream without pauses.

Use it in conjunction with hdparm that enables dma & interrupts.


/*
multi-threaded export_file()

forks send of 1MB block
and while sending reads the next block

use it in conjunction with hdparm that enables dma & interrupts

-- gorilla daddy
*/

#include "mfs.h"

#include <sys/wait.h>

#define BUFSIZE (1024*1024)



int export_file2(int s, u32 fsid)
{
int bufidx=0;
static unsigned char buf[2][BUFSIZE];

int n;
u64 ofs = 0;
u64 size,
total = 0;
int pct,
last_pct;

pid_t send_process;


struct mfs_inode inode;


send_process=0;



mfs_readahead(1);
mfs_fsid_info(fsid);
size = mfs_fsid_size(fsid);
fprintf(stderr, "exporting fsid %d of size %lld to %s\n", fsid, size, "stdout"); fflush(stderr);

last_pct=0;
mfs_load_inode(fsid, &inode);

while (total<size)

{
bufidx^=1;

if ((n=mfs_fsid_pread_inode(&inode, fsid, buf[bufidx], ofs, MIN(BUFSIZE,size-total))) <=0)
break;

if (send_process) {
int status;
waitpid(send_process, &status, 0);
if (WEXITSTATUS(status)!=0) break;
}

if (((u64 *)buf[bufidx])[0]==0 && ((u64 *)buf[bufidx])[1]==0)
{
fprintf(stderr,"skipping blank chunk\n");
}
else
{
if ((send_process=fork())==0) {
if (write(s, buf[bufidx], n) != n)
{
fprintf(stderr,"********** #1 failed to write to %s\n", "stdout"); fflush(stderr);
exit(1);
}
exit(0);
}
}
ofs += n;
total += n;
pct = (100*total)/size;
if (pct != last_pct)
{
fprintf(stderr, "%d%%\r", pct); fflush(stderr);
last_pct = pct;
}
}


return(1);
}