hi. I was playing around with Linux and tmpfs, I made a big bunch of dirs. I really mean BIG. Names were "A" x 2000.
$ rm -rf A* Segmentation fault $ du -sh Segmentation fault $ I have x86 Linux 2.4.18-rc2, glibc-2.2.4-19.3, fileutils-4.1 & 4.1.7. Here gdb debug stuff from v4.1.7: Program received signal SIGSEGV, Segmentation fault. 0x08049e66 in remove_dir (fs=0xbf7cc260, need_save_cwd=0, x=0xbffc8d60, cwd_dev_ino=0xbf7ccb60) at remove.c:656 656 char *dir_name = fs->filename; (gdb) bt #0 0x08049e66 in remove_dir (fs=0xbf7cc260, need_save_cwd=0, x=0xbffc8d60, cwd_dev_ino=0xbf7ccb60) at remove.c:656 #1 0x0804a7e5 in rm (fs=0xbf7cc260, user_specified_name=0, x=0xbffc8d60, cwd_dev_ino=0xbf7ccb60) at remove.c:906 #2 0x08049992 in remove_cwd_entries (x=0xbffc8d60, cwd_dev_ino=0xbf7ccb60) at remove.c:536 #3 0x0804a14d in remove_dir (fs=0xbf7ccd00, need_save_cwd=0, x=0xbffc8d60, cwd_dev_ino=0xbf7cd600) at remove.c:732 #4 0x0804a7e5 in rm (fs=0xbf7ccd00, user_specified_name=0, x=0xbffc8d60, cwd_dev_ino=0xbf7cd600) at remove.c:906 ... (gdb) print *fs $14 = {filename = 0x8053d43 'A' <repeats 200 times>..., have_filetype_mode = 1, have_full_mode = 1, have_device = 1, mode = 16832, st_ino = 38654705664, st_dev = 595832223039488000} (gdb) disass $eip-32 $eip+32 Dump of assembler code from 0x8049e46 to 0x8049e86: 0x8049e46 <remove_file+630>: in (%dx),%eax 0x8049e47 <remove_file+631>: (bad) 0x8049e48 <remove_file+632>: decl 0x26b4(%ebp) 0x8049e4e <remove_file+638>: add %al,(%eax) 0x8049e50 <remove_dir>: push %ebp 0x8049e51 <remove_dir+1>: mov %esp,%ebp 0x8049e53 <remove_dir+3>: push %edi 0x8049e54 <remove_dir+4>: push %esi 0x8049e55 <remove_dir+5>: push %ebx 0x8049e56 <remove_dir+6>: xor %ebx,%ebx 0x8049e58 <remove_dir+8>: sub $0xfc,%esp 0x8049e5e <remove_dir+14>: mov 0x10(%ebp),%edx 0x8049e61 <remove_dir+17>: mov 0x8(%ebp),%eax 0x8049e64 <remove_dir+20>: mov (%eax),%eax 0x8049e66 <remove_dir+22>: mov %eax,0xffffff04(%ebp) <<<=== 0x8049e6c <remove_dir+28>: mov 0x8(%edx),%edx 0x8049e6f <remove_dir+31>: test %edx,%edx 0x8049e71 <remove_dir+33>: je 0x804a5e0 <remove_dir+1936> 0x8049e77 <remove_dir+39>: mov 0x10(%ebp),%ecx 0x8049e7a <remove_dir+42>: mov (%ecx),%edi 0x8049e7c <remove_dir+44>: test %edi,%edi 0x8049e7e <remove_dir+46>: je 0x804a590 <remove_dir+1856> 0x8049e84 <remove_dir+52>: mov 0x10(%ebp),%esi (gdb) print $ebp $16 = (void *) 0xbf7cc0e8 (PAGE_OFFSET - $ebp) is about my stack size (8192 KiB) in resource limits. Can rm/du/etc memory usage be optimized? It needs to keep names of all the dirs it traverses in memory? Hmh, if that's the case, maybe I'll just create a specially crafted rm which can remove those evil dirs (or just umount this time). I don't know if find would work if I had more mem, now kernel says kernel: Out of Memory: Killed process 28099 (find). At least it didn't run out of stack. "ls -R" fails in the beginning with "file name too long". -- Safari - [EMAIL PROTECTED] - PGP key 0x427E7914 - http://iki.fi/safari/ The UNIX Guru's View of Sex: "unzip ; strip ; touch ; finger ; \ mount ; fsck ; more ; yes ; umount ; sleep"
#include <sys/stat.h> #include <string.h> #include <errno.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #define EVILSIZE 2000 int main(void) { char dir_A[EVILSIZE]; memset(dir_A, 'A', EVILSIZE); dir_A[EVILSIZE-1] = 0; while(1) { if(mkdir(dir_A, S_IRWXU) != 0) { if(errno == EEXIST) { if(chdir(dir_A) == 0) { continue; } else { goto plonk; } } fprintf(stderr, "mkdir: %s\n", strerror(errno)); exit(EXIT_FAILURE); } if(chdir(dir_A) != 0) { plonk: fprintf(stderr, "chdir: %s\n", strerror(errno)); exit(EXIT_FAILURE); } } return EXIT_SUCCESS; }