When copying a large file using tftp, if during the course of the transfer the disk of the receiver fills up, tftp will still try and receive more data from the sender ignoring the fact that the write()'s are failing because there is no more space left. Glancing over the tftp code (/usr/src/usr.bin/tftp) I noticed that the function recvfile() in tftp.c is responsible for the reception of a file. Within this function another function called write_behind() is responsible for writing the received data to disk. Although the write_behind() function returns the return value of the write() system call, this return value is never checked in the calling function recvfile(). The result is that tftp will continue recv'ing and subsequently trying to write() the data despite the fact that each call to write() fails. How-To-Repeat: Try tftp'ing a large file onto a filesystem that doesn't have enough room to hold it.
Here is untested patch for -current (applied for RELENG_2_2_0_RELEASE too): Index: tftpd.c =================================================================== RCS file: /home/ncvs/src/libexec/tftpd/tftpd.c,v retrieving revision 1.21 diff -u -r1.21 tftpd.c --- tftpd.c 2001/11/22 05:08:35 1.21 +++ tftpd.c 2002/01/29 16:51:15 @@ -652,7 +652,12 @@ syslog(LOG_ERR, "write: %m"); goto abort; } + errno = 0; write_behind(file, pf->f_convert); + if (errno == ENOSPC) { + nak(ENOSPACE); + goto abort; + } for ( ; ; ) { alarm(rexmtval); n = recv(peer, dp, PKTSIZE, 0); @@ -683,7 +688,12 @@ goto abort; } } while (size == SEGSIZE); + errno = 0; write_behind(file, pf->f_convert); + if (errno == ENOSPC) { + nak(ENOSPACE); + goto abort; + } (void) fclose(file); /* close data file */ ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */ -- Maxim Konovalov, MAcomnet, Internet-Intranet Dept., system engineer phone: +7 (095) 796-9079, mailto: maxim@macomnet.ru
... and for tftp: Index: tftp.c =================================================================== RCS file: /home/ncvs/src/usr.bin/tftp/tftp.c,v retrieving revision 1.7 diff -u -r1.7 tftp.c --- tftp.c 2001/12/11 23:43:15 1.7 +++ tftp.c 2002/01/29 18:13:09 @@ -242,6 +242,10 @@ goto abort; } write_behind(file, convert); + if (errno == ENOSPC ) { + nak(errno + 100); + break; + } for ( ; ; ) { alarm(rexmtval); do { -- Maxim Konovalov, MAcomnet, Internet-Intranet Dept., system engineer phone: +7 (095) 796-9079, mailto: maxim@macomnet.ru
On Tue, Jan 29, 2002 at 10:20:02AM -0800, Maxim Konovalov wrote: [snip] > ... and for tftp: > > Index: tftp.c > =================================================================== > RCS file: /home/ncvs/src/usr.bin/tftp/tftp.c,v > retrieving revision 1.7 > diff -u -r1.7 tftp.c > --- tftp.c 2001/12/11 23:43:15 1.7 > +++ tftp.c 2002/01/29 18:13:09 > @@ -242,6 +242,10 @@ > goto abort; > } > write_behind(file, convert); > + if (errno == ENOSPC ) { > + nak(errno + 100); > + break; > + } > for ( ; ; ) { > alarm(rexmtval); > do { Actually, this should read, Index: tftp.c =================================================================== RCS file: /home/ncvs/src/usr.bin/tftp/tftp.c,v retrieving revision 1.7 diff -u -r1.7 tftp.c --- tftp.c 2001/12/11 23:43:15 1.7 +++ tftp.c 2002/01/29 18:13:09 @@ -242,6 +242,10 @@ goto abort; } write_behind(file, convert); + if (errno == ENOSPC ) { + nak(ENOSPACE); + break; + } for ( ; ; ) { alarm(rexmtval); do { That is, there is a specific error code for this condition specified within the TFTP protocol (RFC 1350). -- Crist J. Clark | cjclark@alum.mit.edu | cjclark@jhu.edu http://people.freebsd.org/~cjc/ | cjc@freebsd.org
State Changed From-To: open->feedback Waiting for the originator to try Maxim's tftpd patch and Crist's tftp patch. Please copy your feedback to <bug-followup@freebsd.org>, using the subject line of this message.
State Changed From-To: feedback->closed Feedback timeout (6 months or more). I will handle any feedback that this closure generates.
Responsible Changed From-To: freebsd-bugs->ceri Feedback timeout (6 months or more). I will handle any feedback that this closure generates.
State Changed From-To: closed->open It is still an issue.
Responsible Changed From-To: ceri->maxim Hope I will commit a fix soon.
I modified Crist's and Maxim's patches slightly to improve error reporting, and to compile for CURRENT. Light testing of out-of-space conditions on both the client and server side succeeded. *** tftp.c.orig Tue Sep 2 20:02:18 2003 --- tftp.c Tue Sep 2 20:08:53 2003 *************** *** 261,270 **** --- 261,275 ---- alarm(0); warn("sendto"); goto abort; } write_behind(file, convert); + if (errno == ENOSPC ) { + nak(ENOSPACE, (struct sockaddr *)&peer); + printf("Transfer aborted (out of space)\n"); + break; + } for ( ; ; ) { alarm(rexmtval); do { fromlen = sizeof(from); n = recvfrom(f, dp, PKTSIZE, 0, *** tftpd.c.orig Tue Sep 2 20:11:48 2003 --- tftpd.c Tue Sep 2 20:38:20 2003 *************** *** 680,690 **** --- 680,696 ---- send_ack: if (send(peer, ackbuf, 4, 0) != 4) { syslog(LOG_ERR, "write: %m"); goto abort; } + errno = 0; write_behind(file, pf->f_convert); + if (errno == ENOSPC) { + nak(ENOSPACE); + syslog(LOG_ERR, "write_behind: %m"); + goto abort; + } for ( ; ; ) { alarm(rexmtval); n = recv(peer, dp, PKTSIZE, 0); alarm(0); if (n < 0) { /* really? */ -- Jason Young, CCIE #8607, MCSE Sr. Network Technician, WAN Technologies (314)817-0131 http://www.wantec.com
Hi Jason, On Wed, 3 Sep 2003, 00:00-0700, Jason A. Young wrote: > The following reply was made to PR misc/34412; it has been noted by GNATS. > > From: "Jason A. Young" <jyoung@power.doogles.com> > To: freebsd-gnats-submit@freebsd.org, <thayton@torrentnet.com> > Cc: > Subject: Re: misc/34412: tftp will still try and receive traffic even after > receiver disk has filled > Date: Wed, 3 Sep 2003 01:56:12 -0500 (CDT) > > I modified Crist's and Maxim's patches slightly to improve error > reporting, and to compile for CURRENT. Light testing of out-of-space > conditions on both the client and server side succeeded. I do not think it is a correct solution for the problem. It is a workaround but a more correct solution is adding an error check to write_behind() and writeit(). See a comment at the top of tftp/tftpsubs.c. Thanks for the effort anyway. -- Maxim Konovalov, maxim@macomnet.ru, maxim@FreeBSD.org
Responsible Changed From-To: maxim->freebsd-bugs Be honest - I do not have a free time to work on this.
Responsible Changed From-To: freebsd-bugs->edwin I'm interested in this patch.
Responsible Changed From-To: edwin->freebsd-bugs Give back into the pool until later.
For bugs matching the following criteria: Status: In Progress Changed: (is less than) 2014-06-01 Reset to default assignee and clear in-progress tags. Mail being skipped
This is no longer an issue. Edwin's tftpd rewrite from 2010 (r207608 and r207614) switched tftpd to buffer the entire file before writing it, rather than write it packet-at-a-time.