kernel: HTTPS through wget, half-close, and /proc/<pid>/fd
busybox wget hands TLS to ssl_client over a socketpair and then does shutdown(SHUT_WR). That cut the AF_UNIX link both ways, so ssl_client's reply was a SIGPIPE and every https:// download hung. SHUT_WR is now a half-close: the peer reads EOF and can still answer. TCP sockets get shutdown() at all (tcp_shutdown for the FIN); it used to do nothing. - exec keeps ignored signals and the signal mask, as execve(2) says. - /proc/<pid>/fd: a link per descriptor -- the path it was opened by, socket:[n], pipe:[n], anon_inode:[eventpoll]. /proc/self too. The global inode bit moves above pid << 8; at 0x10000 it was /proc/256. - fstat on a socket or pipe answers S_IFSOCK / S_IFIFO instead of EINVAL. - poll, select and epoll wake as soon as a pipe, socket or input device changes, not on the next tick. - Pipes are 64 KB of lazily allocated pages, copied in blocks, with PIPE_BUF atomicity: 300 MB through `yes | head | wc` in 7 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
parent
906318f2b6
commit
8351e0323b
15 changed files with 434 additions and 71 deletions
|
|
@ -24,6 +24,7 @@ struct {
|
|||
struct file *free;
|
||||
struct kmem_cache *more;
|
||||
uint n;
|
||||
uint64 serial; // the last ino handed out
|
||||
} ftable;
|
||||
|
||||
void
|
||||
|
|
@ -63,6 +64,8 @@ filealloc(void)
|
|||
ftable.n++;
|
||||
}
|
||||
f->ref = 1;
|
||||
f->ino = ++ftable.serial;
|
||||
f->path = 0;
|
||||
FSSTAT_TAKE(fsstat.file_used, fsstat.file_peak); // 0 -> 1
|
||||
// Cleared here rather than left to the caller: every creator sets
|
||||
// readable/writable/off, but only open() sets nonblock, so a struct file
|
||||
|
|
@ -101,12 +104,16 @@ fileclose(struct file *f)
|
|||
lock_close_file(f);
|
||||
ff = *f;
|
||||
f->ref = 0;
|
||||
f->path = 0;
|
||||
f->type = FD_NONE;
|
||||
f->fnext = ftable.free;
|
||||
ftable.free = f;
|
||||
FSSTAT_DROP(fsstat.file_used); // 1 -> 0
|
||||
release(&ftable.lock);
|
||||
|
||||
if(ff.path)
|
||||
kmfree(ff.path);
|
||||
|
||||
if(ff.type == FD_MEMFD)
|
||||
shm_detach(ff.memfd_seg); // the last mapper frees the pages
|
||||
else if(ff.type == FD_EVENT)
|
||||
|
|
@ -129,6 +136,42 @@ fileclose(struct file *f)
|
|||
}
|
||||
}
|
||||
|
||||
// What /proc/<pid>/fd/N points at, in Linux's spelling: the path, or
|
||||
// "socket:[ino]", "pipe:[ino]", "anon_inode:[eventpoll]". Returns the length.
|
||||
// ftable.lock is what keeps `path` alive: fileclose() takes it from the file
|
||||
// under the lock and frees it after.
|
||||
int
|
||||
file_describe(struct file *f, char *buf, int cap)
|
||||
{
|
||||
const char *pre = 0, *s = 0;
|
||||
int n = 0;
|
||||
|
||||
acquire(&ftable.lock);
|
||||
if(f->ref > 0){
|
||||
switch(f->type){
|
||||
case FD_INODE: s = f->path; if(!s) pre = "inode:["; break;
|
||||
case FD_SOCKET: pre = "socket:["; break;
|
||||
case FD_PIPE: pre = "pipe:["; break;
|
||||
case FD_MEMFD: s = "/memfd: (deleted)"; break;
|
||||
case FD_EVENT: s = ev_kind_name(f->ev); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if(pre){
|
||||
char num[24];
|
||||
int k = 0;
|
||||
uint64 v = f->type == FD_INODE && f->ip ? f->ip->inum : f->ino;
|
||||
do { num[k++] = '0' + v % 10; v /= 10; } while(v);
|
||||
while(*pre && n < cap) buf[n++] = *pre++;
|
||||
while(k && n < cap) buf[n++] = num[--k];
|
||||
if(n < cap) buf[n++] = ']';
|
||||
} else if(s){
|
||||
while(*s && n < cap) buf[n++] = *s++;
|
||||
}
|
||||
release(&ftable.lock);
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
filestat(struct file *f, struct stat *st)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue