From alex@alexwang.com  Wed Apr  7 11:31:52 2004
Return-Path: <alex@alexwang.com>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 1504816A4CE
	for <FreeBSD-gnats-submit@freebsd.org>; Wed,  7 Apr 2004 11:31:52 -0700 (PDT)
Received: from alexwang.com (alexwang.com [61.62.231.187])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 4CC4B43D49
	for <FreeBSD-gnats-submit@freebsd.org>; Wed,  7 Apr 2004 11:31:51 -0700 (PDT)
	(envelope-from alex@alexwang.com)
Received: from alexwang.com (localhost.alexwang.com [127.0.0.1])
	by alexwang.com (8.12.10/8.12.10) with ESMTP id i37IVYA7001226
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 8 Apr 2004 02:31:34 +0800 (CST)
Received: (from root@localhost)
	by alexwang.com (8.12.10/8.12.10/Submit) id i37IVY3K001225;
	Thu, 8 Apr 2004 02:31:34 +0800 (CST)
	(envelope-from alex)
Message-Id: <200404071831.i37IVY3K001225@alexwang.com>
Date: Thu, 8 Apr 2004 02:31:34 +0800 (CST)
From: Alex Wang <alex@alexwang.com>
Reply-To: Alex Wang <alex@alexwang.com>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: Can't use sendfile(2) to download files in UDF DVD
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         65300
>Category:       kern
>Synopsis:       [udf] [patch] Can't use sendfile(2) to download files in UDF DVD
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Apr 07 11:40:15 PDT 2004
>Closed-Date:    Wed Feb 28 12:01:25 GMT 2007
>Last-Modified:  Wed Feb 28 12:01:25 GMT 2007
>Originator:     Alex Wang
>Release:        FreeBSD 5.2-RELEASE i386
>Organization:
>Environment:
System: FreeBSD alexwang.com 5.2-RELEASE FreeBSD 5.2-RELEASE #0: Tue Jan 13 23:04:18 CST 2004 alex@alexwang.com:/usr/src/sys/i386/compile/ALEX i386


	
>Description:
	Files in UDF filesystem can't be downlaod through ftp (sendfile(2)).
	It seems the udf_read() can't map the right vm page.
>How-To-Repeat:
	Just download a file in UDF DVD throught FTP. The file content would
	be very strange.
>Fix:

	


>Release-Note:
>Audit-Trail:

From: "Alex Wang" <alex@alexwang.com>
To: <freebsd-gnats-submit@FreeBSD.org>, "ALEX" <alex@alexwang.com>
Cc:  
Subject: Re: kern/65300: Can't use sendfile(2) to download files in UDF DVD
Date: Fri, 9 Apr 2004 03:06:33 +0800

 This is a multi-part message in MIME format.
 
 ------=_NextPart_000_002E_01C41DDF.A9B7BD00
 Content-Type: text/plain;
 	charset="big5"
 Content-Transfer-Encoding: quoted-printable
 
 I guess the reason is the sendfile(2) get page by the file vp and offset =
 but the udf_read gives bread() device vp and sector. So the bread can't =
 get the same page with sendfile().
 We should give bread file vp and offset. Then transfer into device vp =
 and logical block in udf_strategy.=20
 
 ------=_NextPart_000_002E_01C41DDF.A9B7BD00
 Content-Type: text/html;
 	charset="big5"
 Content-Transfer-Encoding: quoted-printable
 
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
 <HTML><HEAD>
 <META http-equiv=3DContent-Type content=3D"text/html; charset=3Dbig5">
 <META content=3D"MSHTML 6.00.2737.800" name=3DGENERATOR>
 <STYLE></STYLE>
 </HEAD>
 <BODY bgColor=3D#ffffff>
 <DIV><FONT face=3DArial size=3D2>I guess the reason is the sendfile(2) =
 get page by=20
 the file vp and offset but the udf_read gives bread() device vp and =
 sector. So=20
 the bread can't get the same page with sendfile().</FONT></DIV>
 <DIV><FONT face=3DArial size=3D2>We should give bread file vp and =
 offset. Then=20
 transfer into device vp and logical block in udf_strategy.=20
 </FONT></DIV></BODY></HTML>
 
 ------=_NextPart_000_002E_01C41DDF.A9B7BD00--
 

From: Pav Lucistnik <pav@FreeBSD.org>
To: bug-followup@FreeBSD.org, alex@alexwang.com
Cc:  
Subject: Re: kern/65300: [udf] Can't use sendfile(2) to download files in
	UDF DVD
Date: Tue, 09 Jan 2007 02:44:45 +0100

 Please try this patch, it fixes the issue for me. Tested on 6-STABLE,
 should apply and work in -CURRENT too.
 
 Index: udf_vnops.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/fs/udf/udf_vnops.c,v
 retrieving revision 1.58.2.2
 diff -a -u -r1.58.2.2 udf_vnops.c
 --- udf_vnops.c	30 Dec 2006 15:42:11 -0000	1.58.2.2
 +++ udf_vnops.c	9 Jan 2007 01:22:12 -0000
 @@ -339,38 +339,60 @@
  	}
  }
  
 +#define lblkno(udfmp, loc)	((loc) >> (udfmp)->bshift)
 +#define blkoff(udfmp, loc)	((loc) & (udfmp)->bmask)
 +#define lblktosize(imp, blk)	((blk) << (udfmp)->bshift)
 +
  static int
 -udf_read(struct vop_read_args *a)
 +udf_read(struct vop_read_args *ap)
  {
 -	struct vnode *vp = a->a_vp;
 -	struct uio *uio = a->a_uio;
 +	struct vnode *vp = ap->a_vp;
 +	struct uio *uio = ap->a_uio;
  	struct udf_node *node = VTON(vp);
 +	struct udf_mnt *udfmp;
  	struct buf *bp;
 -	uint8_t *data;
 -	off_t fsize, offset;
 +	daddr_t lbn, rablock;
 +	off_t diff, fsize;
  	int error = 0;
 -	int size;
 +	long size, n, on;
  
 +	if (uio->uio_resid == 0)
 +		return (0);
  	if (uio->uio_offset < 0)
  		return (EINVAL);
 -
  	fsize = le64toh(node->fentry->inf_len);
 -
 -	while (uio->uio_offset < fsize && uio->uio_resid > 0) {
 -		offset = uio->uio_offset;
 -		if (uio->uio_resid + offset <= fsize)
 -			size = uio->uio_resid;
 -		else
 -			size = fsize - offset;
 -		error = udf_readatoffset(node, &size, offset, &bp, &data);
 -		if (error == 0)
 -			error = uiomove(data, size, uio);
 -		if (bp != NULL)
 +	udfmp = node->udfmp;
 +	do {
 +		lbn = lblkno(udfmp, uio->uio_offset);
 +		on = blkoff(udfmp, uio->uio_offset);
 +		n = min((u_int)(udfmp->bsize - on),
 +			uio->uio_resid);
 +		diff = fsize - uio->uio_offset;
 +		if (diff <= 0)
 +			return (0);
 +		if (diff < n)
 +			n = diff;
 +		size = udfmp->bsize;
 +		rablock = lbn + 1;
 +		if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
 +			if (lblktosize(udfmp, rablock) < fsize) {
 +				error = cluster_read(vp, fsize, lbn, size, NOCRED,
 +					uio->uio_resid, (ap->a_ioflag >> 16), &bp);
 +			} else {
 +				error = bread(vp, lbn, size, NOCRED, &bp);
 +			}
 +		} else {
 +			error = bread(vp, lbn, size, NOCRED, &bp);
 +		}
 +		n = min(n, size - bp->b_resid);
 +		if (error) {
  			brelse(bp);
 -		if (error)
 -			break;
 -	};
 +			return (error);
 +		}
  
 +		error = uiomove(bp->b_data + on, (int)n, uio);
 +		brelse(bp);
 +	} while (error == 0 && uio->uio_resid > 0 && n != 0);
  	return (error);
  }
  
 @@ -776,23 +798,29 @@
  	struct vnode *vp;
  	struct udf_node *node;
  	int maxsize;
 +	daddr_t sector;
  	struct bufobj *bo;
 +	int multiplier;
  
  	bp = a->a_bp;
  	vp = a->a_vp;
  	node = VTON(vp);
  
 -	/* cd9660 has this test reversed, but it seems more logical this way */
 -	if (bp->b_blkno != bp->b_lblkno) {
 +	if (bp->b_blkno == bp->b_lblkno) {
  		/*
  		 * Files that are embedded in the fentry don't translate well
  		 * to a block number.  Reject.
  		 */
  		if (udf_bmap_internal(node, bp->b_lblkno * node->udfmp->bsize,
 -		    &bp->b_lblkno, &maxsize)) {
 +		    &sector, &maxsize)) {
  			clrbuf(bp);
  			bp->b_blkno = -1;
  		}
 +
 +		/* bmap gives sector numbers, bio works with device blocks */
 +		multiplier = node->udfmp->bsize / DEV_BSIZE;
 +		bp->b_blkno = sector * multiplier;
 +
  	}
  	if ((long)bp->b_blkno == -1) {
  		bufdone(bp);
 
 -- 
 Pav Lucistnik <pav@oook.cz>
               <pav@FreeBSD.org>
 
 It's ten o'clock; do you know where your processes are?
State-Changed-From-To: open->feedback 
State-Changed-By: remko 
State-Changed-When: Tue Jan 9 06:19:42 UTC 2007 
State-Changed-Why:  
Pav submitted a patch, can you please try this and let us know the results? 

http://www.freebsd.org/cgi/query-pr.cgi?pr=65300 
State-Changed-From-To: feedback->closed 
State-Changed-By: remko 
State-Changed-When: Wed Feb 28 12:01:24 UTC 2007 
State-Changed-Why:  
No feedback, no game, close the ticket. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=65300 
>Unformatted:
