I am studying the linux file system. I had an experiment to explore how linux saves the hard links.
I made 1000 hard links for a file in the same directory. The size of .(DOT) increased to 28672; I remove 500 hard links, the size of .(DOT) did not decrease. (I used "stat ." to check the size.) Why doesn't the size decrease?
This is my experiment:
I have a folder named test, which has only one small file testfile and a script, the status was like this:
York:~/test$ ll -li
total 84
7995940 drwxr-xr-x 2 York domain_users 4096 Jul 17 19:20 ./
7995939 drwxr-xr-x 3 York domain_users 69632 Jul 17 19:20 ../
7996494 -rwxrwxrwx 1 York domain_users 94 Jul 17 19:14 copy.sh*
8026281 -rw-r--r-- 1 York domain_users 7 Jul 17 19:17 testfile
York:~/test$ stat .
File: `.'
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: fc03h/64515d Inode: 7995940 Links: 2
Access: (0755/drwxr-xr-x) Uid: (2060469376/York) Gid: (2060452353/domain_users)
Access: 2015-07-17 19:20:06.288345960 +0200
Modify: 2015-07-17 19:20:05.420340318 +0200
Change: 2015-07-17 19:20:05.420340318 +0200
Birth: -
Then I ran the script:
for i in `seq 200000 200999`;
do
ln testfile "$i"
done
After that, I got the following result:
York:~/test$ stat .
File: `.'
Size: 28672 Blocks: 64 IO Block: 4096 directory
Device: fc03h/64515d Inode: 7995940 Links: 2
Access: (0755/drwxr-xr-x) Uid: (2060469376/York) Gid: (2060452353/domain_users)
Access: 2015-07-17 19:21:25.364862751 +0200
Modify: 2015-07-17 19:21:11.064768884 +0200
Change: 2015-07-17 19:21:11.064768884 +0200
Birth: -
And I could see that the inode counter is 1001, which was what I expected:
York:~/test$ ll -li testfile
8026281 -rw-r--r-- 1001 York domain_users 7 Jul 17 19:17 testfile
I used "rm" to remove 500 hard links, I saw:
York:~/test$ ll -li testfile
8026281 -rw-r--r-- 501 York domain_users 7 Jul 17 19:17 testfile
But the size of the directory did not decrease:
York:~/test$ stat .
File: `.'
Size: 28672 Blocks: 64 IO Block: 4096 directory
Device: fc03h/64515d Inode: 7995940 Links: 2
Access: (0755/drwxr-xr-x) Uid: (2060469376/York) Gid: (2060452353/domain_users)
Access: 2015-07-17 19:24:35.138125221 +0200
Modify: 2015-07-17 19:24:35.142125246 +0200
Change: 2015-07-17 19:24:35.142125246 +0200
Birth: -
My understanding about the directory in file system is like this: For each directory, an inode is allocated for attributions like folder name etc, and also a block of data is used to keep entries for files and directories in that folder. Because each hard link needs one entry, 1000 hard links need more space than a block of data, another data blocks are needed. So the size of the directory .(DOT) increases. Vise versa, if I remove 500 hard links, the size should decrease.
But the experiment showed that the size did not decrease. Where am I wrong?
Thank you in advance!
Best Wishes,
York
What you're seeing is correct. Many Linux filesystems never shrink the size of a directory inode; they just blank out the entries for deleted files, allowing them to be reused if more files are added to the directory later. The only way to return the directory to its original size may be to delete it and create a new one with the same name.
Frequently, inodes are implemented on b-trees and as a minor optimization, the can grow as needed, but don't collapse.
Related
A symbolic link created by zfs is returning as ../../zd0, tested through multiple ways to check. Not sure why the result is not /dev/zd0 as that is the actual link as far as I am aware.
admin#r2-compute1:~$ ls -l /dev/zvol/cpool/cinder-volumes
lrwxrwxrwx 1 root root 9 Jun 25 09:53 /dev/zvol/cpool/cinder-volumes -> ../../zd0
admin#r2-compute1:~$ stat /dev/zvol/cpool/cinder-volumes
File: /dev/zvol/cpool/cinder-volumes -> ../../zd0
Size: 9 Blocks: 0 IO Block: 4096 symbolic link
Device: 6h/6d Inode: 640 Links: 1
Access: (0777/lrwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2020-06-25 10:07:28.610707769 -0700
Modify: 2020-06-25 09:53:52.174435310 -0700
Change: 2020-06-25 09:53:52.174435310 -0700
Birth: -
admin#r2-compute1:~$ file /dev/zvol/cpool/cinder-volumes
/dev/zvol/cpool/cinder-volumes: symbolic link to ../../zd0
I am working with openstack and zfs and am wondering why the symbolic link returns "../../zd0" instead of "dev/zd0". I am not sure what the ../../ means and understanding would assist in my openstack implementation understanding. First time posting and Google and SymbolHound did not produce any results in regards to the meaning behind ../../
Thank you!
Probably while creating the soft links ../../zd0 was adopted instead of the full path /dev/zd0 (or whatever the path was supposed to be given).
If absolutely necessary, you may try to unlink this first and recreate the link by providing FULL-PATH to the DEVICE/FILE.
NOTE: Try this with caution and ensure the paths are correct, this is just the symbolic code to help you correct the error:
unlink /dev/zvol/cpool/cinder-volumes
ln -s /dev/zvol/cpool/cinder-volumes /dev/zd0
In case it matters: I stumbled over this problem when backing up a directory using rsync in a Cygwin environment, and rsync suddenly gave the error message:
rsync: readdir("/cygdrive/d/portable/FirefoxPortable/Data/profile/storage/default/moz-extension+++4c6d0e71-68ce-470e-87aa-8db1a3f6524d^userContextId=4294967295/idb"): File exists (17)
Here, /cygdrive/d/portable/FirefoxPortable is the directory to be saved, and until now, this has worked fine. Suspecting that the real problem is not related to rsync, I did a
ls /cygdrive/d/portable/FirefoxPortable/Data/profile/storage/default/moz-extension+++4c6d0e71-68ce-470e-87aa-8db1a3f6524d^userContextId=4294967295/idb
and indeed got the error message
ls: reading directory '/cygdrive/d/portable/FirefoxPortable/Data/profile/storage/default/moz-extension+++4c6d0e71-68ce-470e-87aa-8db1a3f6524d^userContextId=4294967295/idb': File exists
So, idb is a directory (which is true), because ls says that it is reading this direcory, but why do I get a File exists error for a directory?
ls -ld /cygdrive/d/portable/FirefoxPortable/Data/profile/storage/default/moz-extension+++4c6d0e71-68ce-470e-87aa-8db1a3f6524d^userContextId=4294967295/idb
yields
drwxr-xr-x 1 FISRONA Domain Users 0 May 6 2019 '/cygdrive/d/portable/FirefoxPortable/Data/profile/storage/default/moz-extension+++4c6d0e71-68ce-470e-87aa-8db1a3f6524d^userContextId=4294967295/idb'
and
stat /cygdrive/d/portable/FirefoxPortable/Data/profile/storage/default/moz-extension+++4c6d0e71-68ce-470e-87aa-8db1a3f6524d^userContextId=4294967295/idb
displayed:
File: /cygdrive/d/portable/FirefoxPortable/Data/profile/storage/default/moz-extension+++4c6d0e71-68ce-470e-87aa-8db1a3f6524d^userContextId=4294967295/idb
Size: 0 Blocks: 0 IO Block: 65536 directory
Device: 5a61dfech/1516363756d Inode: 12873190524118251466 Links: 1
Access: (0755/drwxr-xr-x) Uid: (3672028/ FISRONA) Gid: (1049089/Domain Users)
Access: 2019-05-06 11:32:50.000000000 +0200
Modify: 2019-05-06 11:32:50.190000000 +0200
Change: 2019-05-06 11:32:50.190000000 +0200
Birth: 2019-05-06 11:32:50.190000000 +0200
What could be messed up here to cause this behaviour?
BTW, I also checked the parent directory (because sometimes, differences in upper/lower case filenames can result in odd effects under Cygwin, due to the underlying Windows operating system):
ls -l /cygdrive/d/portable/FirefoxPortable/Data/profile/storage/default/moz-extension+++4c6d0e71-68ce-470e-87aa-8db1a3f6524d^userContextId=4294967295/
total 0
drwxr-xr-x 1 FISRONA Domain Users 0 May 6 2019 idb
I read a name file, just the name and I need to print inode-number, the number of hard-links and others. How do I do that?
I thought initially to add the absolute path to my name file but I do not know how to that.
Use the stat command. Here is an example output:
UbuntuVBox:~/stackOver$ stat main.cpp
File: ‘main.cpp’
Size: 234 Blocks: 8 IO Block: 4096 regular file
Device: 801h/2049d Inode: 18749058 Links: 1
Access: (0664/-rw-rw-r--) Uid: ( 1000/ root) Gid: ( 1000/ root)
Access: 2016-06-01 10:02:55.858362281 +0100
Modify: 2016-06-01 10:02:48.770820244 +0100
Change: 2016-06-01 10:02:48.782826244 +0100
Birth: -
As you can see you get the inode number and number of links amongst other things.
I am running Centos 7 kernel 3.10.0 on Oracle's VirtualBox 4.3.20 with an ext4 filesystem.
It seems that setting the "A" flag on a file doesn't keep the access time field from updating.
I created a file and used stat to check the access time -
touch ./foo
stat ./foo
which returns the following
File: ./foo
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: fd01h/64769d Inode: 1444417 Links: 1
Access: (0777/-rwxrwxrwx) Uid: ( 1000/ user_1) Gid: ( 1000/ user_1)
Context: unconfined_u:object_r:user_home_t:s0
Access: 2015-08-02 11:52:23.451524456 -0700
Modify: 2015-08-02 11:52:23.451524456 -0700
Change: 2015-08-02 11:52:23.451524456 -0700
Birth: -
If I then change the attribute and rerun stat -
sudo chattr +A ./foo
stat ./foo
I get the following which (I think) shows the access time value as updated?
File: ./foo
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: fd01h/64769d Inode: 1444417 Links: 1
Access: (0777/-rwxrwxrwx) Uid: ( 1000/ user_1) Gid: ( 1000/ user_1)
Context: unconfined_u:object_r:user_home_t:s0
Access: 2015-08-02 11:53:32.400974020 -0700
Modify: 2015-08-02 11:53:32.400974020 -0700
Change: 2015-08-02 11:53:32.400974020 -0700
Birth: -
Am I misunderstanding the use of the A flag? I thought it would keep the access time from changing?
Thanks for any insights you can offer. I am just trying to understand how things work.
Rog
+A will keep the same atime when you open the file with vi for example and not modify it. The result you've posted after modifying the attribute doesn't look right to me. Changing the attribute should only affect the 'Change' timestamp. In your case, all 3 timestamps are the same.
I tried lseek and dd if=/dev/urandom seek=7 bs=4096 count=2 of=fwh, they didn't work on my computer. The ls -lks result is:
44 -rw-rw-r-- 1 guangmu guangmu 36864 Aug 10 18:19 fwh.
I tried rm the file, reboot, and even cleaning the blocks used by fwt via debugfs. These didn't help.
My filesystem is ext4, OS is ubuntu 14.04. Here is the result of sudo tune2fs -l /dev/sda5:
tune2fs 1.42.9 (4-Feb-2014)
Filesystem volume name:
Last mounted on: /
Filesystem UUID: e051336c-6a7a-4683-9c24-1230676170b1
Filesystem magic number: 0xEF53
Filesystem revision #: 1 (dynamic)
Filesystem features: has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags: signed_directory_hash
Default mount options: user_xattr acl
Filesystem state: clean
Errors behavior: Continue
Filesystem OS type: Linux
Inode count: 34594816
Block count: 138359808
Reserved block count: 6917990
Free blocks: 109566416
Free inodes: 33280312
First block: 0
Block size: 4096
Fragment size: 4096
Reserved GDT blocks: 991
Blocks per group: 32768
Fragments per group: 32768
Inodes per group: 8192
Inode blocks per group: 512
Flex block group size: 16
Filesystem created: Mon Jan 20 20:56:20 2014
Last mount time: Mon Aug 11 11:08:31 2014
Last write time: Mon Aug 11 11:08:30 2014
Mount count: 387
Maximum mount count: -1
Last checked: Mon Jan 20 20:56:20 2014
Check interval: 0 ()
Lifetime writes: 743 GB
Reserved blocks uid: 0 (user root)
Reserved blocks gid: 0 (group root)
First inode: 11
Inode size: 256
Required extra isize: 28
Desired extra isize: 28
Journal inode: 8
First orphan inode: 18877404
Default directory hash: half_md4
Directory Hash Seed: 780cc1b8-1fa1-4751-9385-270b563b29cd
Journal backup: inode blocks
Did I do something wrong?
No, that is correct. You have seeked (or sought maybe?) 7 blocks of 4096 bytes in fwh and then written 2 blocks of 4096 bytes to it. So you would expect fwh to contain 9 blocks of 4096 bytes, which is 36,864 bytes - exactly as you have.
Or have I missed something? What were you expecting?
It's my carelessness.:(
/home is mounted as ecrpyptfs, which doesn't support sparse file.