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) */ |