diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2012-02-06 12:45:27 -0500 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-03-20 21:29:32 -0400 |
| commit | 8de52778798fe39660a8d6b26f290e0c93202761 (patch) | |
| tree | 56384beb7863c1f338f2b66b509bf58eea5a99c2 /fs/sysv | |
| parent | c16fa4f2ad19908a47c63d8fa436a1178438c7e7 (diff) | |
vfs: check i_nlink limits in vfs_{mkdir,rename_dir,link}
New field of struct super_block - ->s_max_links. Maximal allowed
value of ->i_nlink or 0; in the latter case all checks still need
to be done in ->link/->mkdir/->rename instances. Note that this
limit applies both to directoris and to non-directories.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/sysv')
| -rw-r--r-- | fs/sysv/namei.c | 12 | ||||
| -rw-r--r-- | fs/sysv/super.c | 24 | ||||
| -rw-r--r-- | fs/sysv/sysv.h | 1 |
3 files changed, 13 insertions, 24 deletions
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index b217797e621b..d7466e293614 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c | |||
| @@ -121,9 +121,6 @@ static int sysv_link(struct dentry * old_dentry, struct inode * dir, | |||
| 121 | { | 121 | { |
| 122 | struct inode *inode = old_dentry->d_inode; | 122 | struct inode *inode = old_dentry->d_inode; |
| 123 | 123 | ||
| 124 | if (inode->i_nlink >= SYSV_SB(inode->i_sb)->s_link_max) | ||
| 125 | return -EMLINK; | ||
| 126 | |||
| 127 | inode->i_ctime = CURRENT_TIME_SEC; | 124 | inode->i_ctime = CURRENT_TIME_SEC; |
| 128 | inode_inc_link_count(inode); | 125 | inode_inc_link_count(inode); |
| 129 | ihold(inode); | 126 | ihold(inode); |
| @@ -134,10 +131,8 @@ static int sysv_link(struct dentry * old_dentry, struct inode * dir, | |||
| 134 | static int sysv_mkdir(struct inode * dir, struct dentry *dentry, umode_t mode) | 131 | static int sysv_mkdir(struct inode * dir, struct dentry *dentry, umode_t mode) |
| 135 | { | 132 | { |
| 136 | struct inode * inode; | 133 | struct inode * inode; |
| 137 | int err = -EMLINK; | 134 | int err; |
| 138 | 135 | ||
| 139 | if (dir->i_nlink >= SYSV_SB(dir->i_sb)->s_link_max) | ||
| 140 | goto out; | ||
| 141 | inode_inc_link_count(dir); | 136 | inode_inc_link_count(dir); |
| 142 | 137 | ||
| 143 | inode = sysv_new_inode(dir, S_IFDIR|mode); | 138 | inode = sysv_new_inode(dir, S_IFDIR|mode); |
| @@ -251,11 +246,6 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry, | |||
| 251 | drop_nlink(new_inode); | 246 | drop_nlink(new_inode); |
| 252 | inode_dec_link_count(new_inode); | 247 | inode_dec_link_count(new_inode); |
| 253 | } else { | 248 | } else { |
| 254 | if (dir_de) { | ||
| 255 | err = -EMLINK; | ||
| 256 | if (new_dir->i_nlink >= SYSV_SB(new_dir->i_sb)->s_link_max) | ||
| 257 | goto out_dir; | ||
| 258 | } | ||
| 259 | err = sysv_add_link(new_dentry, old_inode); | 249 | err = sysv_add_link(new_dentry, old_inode); |
| 260 | if (err) | 250 | if (err) |
| 261 | goto out_dir; | 251 | goto out_dir; |
diff --git a/fs/sysv/super.c b/fs/sysv/super.c index f60c196913ea..f467740e088c 100644 --- a/fs/sysv/super.c +++ b/fs/sysv/super.c | |||
| @@ -44,7 +44,7 @@ enum { | |||
| 44 | JAN_1_1980 = (10*365 + 2) * 24 * 60 * 60 | 44 | JAN_1_1980 = (10*365 + 2) * 24 * 60 * 60 |
| 45 | }; | 45 | }; |
| 46 | 46 | ||
| 47 | static void detected_xenix(struct sysv_sb_info *sbi) | 47 | static void detected_xenix(struct sysv_sb_info *sbi, unsigned *max_links) |
| 48 | { | 48 | { |
| 49 | struct buffer_head *bh1 = sbi->s_bh1; | 49 | struct buffer_head *bh1 = sbi->s_bh1; |
| 50 | struct buffer_head *bh2 = sbi->s_bh2; | 50 | struct buffer_head *bh2 = sbi->s_bh2; |
| @@ -59,7 +59,7 @@ static void detected_xenix(struct sysv_sb_info *sbi) | |||
| 59 | sbd2 = (struct xenix_super_block *) (bh2->b_data - 512); | 59 | sbd2 = (struct xenix_super_block *) (bh2->b_data - 512); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | sbi->s_link_max = XENIX_LINK_MAX; | 62 | *max_links = XENIX_LINK_MAX; |
| 63 | sbi->s_fic_size = XENIX_NICINOD; | 63 | sbi->s_fic_size = XENIX_NICINOD; |
| 64 | sbi->s_flc_size = XENIX_NICFREE; | 64 | sbi->s_flc_size = XENIX_NICFREE; |
| 65 | sbi->s_sbd1 = (char *)sbd1; | 65 | sbi->s_sbd1 = (char *)sbd1; |
| @@ -75,7 +75,7 @@ static void detected_xenix(struct sysv_sb_info *sbi) | |||
| 75 | sbi->s_nzones = fs32_to_cpu(sbi, sbd1->s_fsize); | 75 | sbi->s_nzones = fs32_to_cpu(sbi, sbd1->s_fsize); |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | static void detected_sysv4(struct sysv_sb_info *sbi) | 78 | static void detected_sysv4(struct sysv_sb_info *sbi, unsigned *max_links) |
| 79 | { | 79 | { |
| 80 | struct sysv4_super_block * sbd; | 80 | struct sysv4_super_block * sbd; |
| 81 | struct buffer_head *bh1 = sbi->s_bh1; | 81 | struct buffer_head *bh1 = sbi->s_bh1; |
| @@ -86,7 +86,7 @@ static void detected_sysv4(struct sysv_sb_info *sbi) | |||
| 86 | else | 86 | else |
| 87 | sbd = (struct sysv4_super_block *) bh2->b_data; | 87 | sbd = (struct sysv4_super_block *) bh2->b_data; |
| 88 | 88 | ||
| 89 | sbi->s_link_max = SYSV_LINK_MAX; | 89 | *max_links = SYSV_LINK_MAX; |
| 90 | sbi->s_fic_size = SYSV_NICINOD; | 90 | sbi->s_fic_size = SYSV_NICINOD; |
| 91 | sbi->s_flc_size = SYSV_NICFREE; | 91 | sbi->s_flc_size = SYSV_NICFREE; |
| 92 | sbi->s_sbd1 = (char *)sbd; | 92 | sbi->s_sbd1 = (char *)sbd; |
| @@ -103,7 +103,7 @@ static void detected_sysv4(struct sysv_sb_info *sbi) | |||
| 103 | sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize); | 103 | sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize); |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | static void detected_sysv2(struct sysv_sb_info *sbi) | 106 | static void detected_sysv2(struct sysv_sb_info *sbi, unsigned *max_links) |
| 107 | { | 107 | { |
| 108 | struct sysv2_super_block *sbd; | 108 | struct sysv2_super_block *sbd; |
| 109 | struct buffer_head *bh1 = sbi->s_bh1; | 109 | struct buffer_head *bh1 = sbi->s_bh1; |
| @@ -114,7 +114,7 @@ static void detected_sysv2(struct sysv_sb_info *sbi) | |||
| 114 | else | 114 | else |
| 115 | sbd = (struct sysv2_super_block *) bh2->b_data; | 115 | sbd = (struct sysv2_super_block *) bh2->b_data; |
| 116 | 116 | ||
| 117 | sbi->s_link_max = SYSV_LINK_MAX; | 117 | *max_links = SYSV_LINK_MAX; |
| 118 | sbi->s_fic_size = SYSV_NICINOD; | 118 | sbi->s_fic_size = SYSV_NICINOD; |
| 119 | sbi->s_flc_size = SYSV_NICFREE; | 119 | sbi->s_flc_size = SYSV_NICFREE; |
| 120 | sbi->s_sbd1 = (char *)sbd; | 120 | sbi->s_sbd1 = (char *)sbd; |
| @@ -131,14 +131,14 @@ static void detected_sysv2(struct sysv_sb_info *sbi) | |||
| 131 | sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize); | 131 | sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize); |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | static void detected_coherent(struct sysv_sb_info *sbi) | 134 | static void detected_coherent(struct sysv_sb_info *sbi, unsigned *max_links) |
| 135 | { | 135 | { |
| 136 | struct coh_super_block * sbd; | 136 | struct coh_super_block * sbd; |
| 137 | struct buffer_head *bh1 = sbi->s_bh1; | 137 | struct buffer_head *bh1 = sbi->s_bh1; |
| 138 | 138 | ||
| 139 | sbd = (struct coh_super_block *) bh1->b_data; | 139 | sbd = (struct coh_super_block *) bh1->b_data; |
| 140 | 140 | ||
| 141 | sbi->s_link_max = COH_LINK_MAX; | 141 | *max_links = COH_LINK_MAX; |
| 142 | sbi->s_fic_size = COH_NICINOD; | 142 | sbi->s_fic_size = COH_NICINOD; |
| 143 | sbi->s_flc_size = COH_NICFREE; | 143 | sbi->s_flc_size = COH_NICFREE; |
| 144 | sbi->s_sbd1 = (char *)sbd; | 144 | sbi->s_sbd1 = (char *)sbd; |
| @@ -154,12 +154,12 @@ static void detected_coherent(struct sysv_sb_info *sbi) | |||
| 154 | sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize); | 154 | sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize); |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | static void detected_v7(struct sysv_sb_info *sbi) | 157 | static void detected_v7(struct sysv_sb_info *sbi, unsigned *max_links) |
| 158 | { | 158 | { |
| 159 | struct buffer_head *bh2 = sbi->s_bh2; | 159 | struct buffer_head *bh2 = sbi->s_bh2; |
| 160 | struct v7_super_block *sbd = (struct v7_super_block *)bh2->b_data; | 160 | struct v7_super_block *sbd = (struct v7_super_block *)bh2->b_data; |
| 161 | 161 | ||
| 162 | sbi->s_link_max = V7_LINK_MAX; | 162 | *max_links = V7_LINK_MAX; |
| 163 | sbi->s_fic_size = V7_NICINOD; | 163 | sbi->s_fic_size = V7_NICINOD; |
| 164 | sbi->s_flc_size = V7_NICFREE; | 164 | sbi->s_flc_size = V7_NICFREE; |
| 165 | sbi->s_sbd1 = (char *)sbd; | 165 | sbi->s_sbd1 = (char *)sbd; |
| @@ -290,7 +290,7 @@ static char *flavour_names[] = { | |||
| 290 | [FSTYPE_AFS] = "AFS", | 290 | [FSTYPE_AFS] = "AFS", |
| 291 | }; | 291 | }; |
| 292 | 292 | ||
| 293 | static void (*flavour_setup[])(struct sysv_sb_info *) = { | 293 | static void (*flavour_setup[])(struct sysv_sb_info *, unsigned *) = { |
| 294 | [FSTYPE_XENIX] = detected_xenix, | 294 | [FSTYPE_XENIX] = detected_xenix, |
| 295 | [FSTYPE_SYSV4] = detected_sysv4, | 295 | [FSTYPE_SYSV4] = detected_sysv4, |
| 296 | [FSTYPE_SYSV2] = detected_sysv2, | 296 | [FSTYPE_SYSV2] = detected_sysv2, |
| @@ -310,7 +310,7 @@ static int complete_read_super(struct super_block *sb, int silent, int size) | |||
| 310 | 310 | ||
| 311 | sbi->s_firstinodezone = 2; | 311 | sbi->s_firstinodezone = 2; |
| 312 | 312 | ||
| 313 | flavour_setup[sbi->s_type](sbi); | 313 | flavour_setup[sbi->s_type](sbi, &sb->s_max_links); |
| 314 | 314 | ||
| 315 | sbi->s_truncate = 1; | 315 | sbi->s_truncate = 1; |
| 316 | sbi->s_ndatazones = sbi->s_nzones - sbi->s_firstdatazone; | 316 | sbi->s_ndatazones = sbi->s_nzones - sbi->s_firstdatazone; |
diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h index 0e4b821c5691..11b07672f6c5 100644 --- a/fs/sysv/sysv.h +++ b/fs/sysv/sysv.h | |||
| @@ -24,7 +24,6 @@ struct sysv_sb_info { | |||
| 24 | char s_bytesex; /* bytesex (le/be/pdp) */ | 24 | char s_bytesex; /* bytesex (le/be/pdp) */ |
| 25 | char s_truncate; /* if 1: names > SYSV_NAMELEN chars are truncated */ | 25 | char s_truncate; /* if 1: names > SYSV_NAMELEN chars are truncated */ |
| 26 | /* if 0: they are disallowed (ENAMETOOLONG) */ | 26 | /* if 0: they are disallowed (ENAMETOOLONG) */ |
| 27 | nlink_t s_link_max; /* max number of hard links to a file */ | ||
| 28 | unsigned int s_inodes_per_block; /* number of inodes per block */ | 27 | unsigned int s_inodes_per_block; /* number of inodes per block */ |
| 29 | unsigned int s_inodes_per_block_1; /* inodes_per_block - 1 */ | 28 | unsigned int s_inodes_per_block_1; /* inodes_per_block - 1 */ |
| 30 | unsigned int s_inodes_per_block_bits; /* log2(inodes_per_block) */ | 29 | unsigned int s_inodes_per_block_bits; /* log2(inodes_per_block) */ |
