Thursday, May 17, 2007

 

Re-linking an unlinked file with fsdb

Given that you have an unlinked file on a file system, how do you relink it into the file system?

One of the things you can do is just work around the problem. You could just copy /proc/XXX/fd/Y, which gets you the contents of the file but not the actual file itself.

What you really want to be able to do is "ln /proc/XXX/fd/Y /some/dir/foo". Theoretically, there's no reason why this shouldn't work, given that you know the inode number of the unlinked file within its file system via /proc/XXX/fd/Y, but it doesn't currently work to do this.

I tried the following with fsdb (on Solaris on a UFS file system), and it worked to relink the file into the file system. Doing something like this isn't generally advisable, as it involves manipulating the disk directly. This bypasses the file-caching mechanism in the kernel, so you'll end up with a disk image that doesn't match what the kernel thinks it should look like. In my case, things were fine after a reboot and fsck, but I may simply have gotten lucky.

(I was prompted to try this after discovering that it's possible to unlink(1M) a non-empty directory. I was curious to see whether or not the inodes in that directory were orphaned by doing so, and it turns out that they are. Given that I had a file system with orphaned inodes, I wanted to see if I could remedy the situation. I was mostly interested to see if I could fix the live file system, which I was unfortunately unable to do.)

# fsdb -o w /dev/md/rdsk/d1
fsdb of /dev/md/rdsk/d1 (Opened for write) -- last mounted on /var
fs_clean is currently set to FSLOG
fs_state consistent (fs_clean CAN be trusted)
/dev/md/rdsk/d1 > :cd tmp
/dev/md/rdsk/d1 > :ls -l
/tmp:
i#: b6          ./
i#: 2           ../
i#: 4d9a        .java/
i#: 1279        SMB--0A40081A-044_0
i#: 4dbd        autosave/
i#: 4970        chadfoo/
i#: 127b        cifs_0
i#: 127c        host_0
i#: 4d9e        mancache/
i#: 1277        named.pid
i#: 1276        named.run
i#: 127a        smb--0a40081a-044_0
/dev/md/rdsk/d1 >

The unlinked file that I'm concerned about existed in the chadfoo directory. (Not that this really matters, given that the scope of the name space for these inode numbers is /var, but I want to link it back to its original location.)

The plan is to create an empty file ("bigfile") in /var/tmp/chadfoo and use fsdb to change the inode number for that particular directory entry to be that of the unlinked file. So that I don't lose the inode of the empty file, I create a second link to it, "bigfile2", and I fix link counts afterwards so that everything's kosher.

Here, I look at the directory entries for inode 4970 (/var/tmp/chadfoo):

/dev/md/rdsk/d1 > 4970:inode; 0:dir?d
i#: 4970        .
/dev/md/rdsk/d1 > 4970:inode; 1:dir?d
i#: b6          ..
/dev/md/rdsk/d1 > 4970:inode; 2:dir?d
i#: 4a62        bigfile
/dev/md/rdsk/d1 > 4970:inode; 3:dir?d
i#: 4a62        bigfile2
/dev/md/rdsk/d1 >

And then I set the inode number for directory entry number 2 to be that of the unlinked file (decimal 19037):

/dev/md/rdsk/d1 > 4970:inode; 2:dir=0t19037
i#: 4a5d        bigfile
/dev/md/rdsk/d1 >

What I've done doesn't change the link counts, though, so I need to do this manually:

/dev/md/rdsk/d1 > 4a62:inode?i
i#: 4a62           md: ----rw-r--r--  uid: 2d85          gid: a
ln: 2              bs: 0              sz : c_flags : 0           0

        accessed: Wed May 16 11:12:22 2007
        modified: Wed May 16 11:12:22 2007
        created : Wed May 16 11:13:02 2007
/dev/md/rdsk/d1 > :ln=1
i#: 4a62           md: ----rw-r--r--  uid: 2d85          gid: a
ln: 1              bs: 0              sz : c_flags : 0           0

        accessed: Wed May 16 11:12:22 2007
        modified: Wed May 16 11:12:22 2007
        created : Wed May 16 11:13:02 2007
/dev/md/rdsk/d1 > 4a5d:inode?i
i#: 4a5d           md: ----rw-r--r--  uid: 2d85          gid: a
ln: 0              bs: 200410         sz : c_flags : 0           40000000

db#0: 28e00        db#1: 28e48        db#2: 28e50        db#3: 28e58
db#4: 28e60        db#5: 28e68        db#6: 28e70        db#7: 28e78
db#8: 28e80        db#9: 28e88        db#a: 28e90        db#b: 28e98
ib#0: 204748       ib#1: cc808
        accessed: Wed May 16 10:39:20 2007
        modified: Wed May 16 10:39:44 2007
        created : Wed May 16 10:39:44 2007
/dev/md/rdsk/d1 > :ln=1
i#: 4a5d           md: ----rw-r--r--  uid: 2d85          gid: a
ln: 1              bs: 200410         sz : c_flags : 0           40000000

db#0: 28e00        db#1: 28e48        db#2: 28e50        db#3: 28e58
db#4: 28e60        db#5: 28e68        db#6: 28e70        db#7: 28e78
db#8: 28e80        db#9: 28e88        db#a: 28e90        db#b: 28e98
ib#0: 204748       ib#1: cc808
        accessed: Wed May 16 10:39:20 2007
        modified: Wed May 16 10:39:44 2007
        created : Wed May 16 10:39:44 2007
/dev/md/rdsk/d1 >

And at this point, I reboot into single user, fsck /var (which shows a few problems to be corrected), and things are fine.


Comments: Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?