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/namei.c | |
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/namei.c')
-rw-r--r-- | fs/namei.c | 13 |
1 files changed, 13 insertions, 0 deletions
diff --git a/fs/namei.c b/fs/namei.c index 46ea9cc16647..a0b82762e8fc 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2569,6 +2569,7 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d | |||
2569 | int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | 2569 | int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) |
2570 | { | 2570 | { |
2571 | int error = may_create(dir, dentry); | 2571 | int error = may_create(dir, dentry); |
2572 | unsigned max_links = dir->i_sb->s_max_links; | ||
2572 | 2573 | ||
2573 | if (error) | 2574 | if (error) |
2574 | return error; | 2575 | return error; |
@@ -2581,6 +2582,9 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
2581 | if (error) | 2582 | if (error) |
2582 | return error; | 2583 | return error; |
2583 | 2584 | ||
2585 | if (max_links && dir->i_nlink >= max_links) | ||
2586 | return -EMLINK; | ||
2587 | |||
2584 | error = dir->i_op->mkdir(dir, dentry, mode); | 2588 | error = dir->i_op->mkdir(dir, dentry, mode); |
2585 | if (!error) | 2589 | if (!error) |
2586 | fsnotify_mkdir(dir, dentry); | 2590 | fsnotify_mkdir(dir, dentry); |
@@ -2911,6 +2915,7 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn | |||
2911 | int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) | 2915 | int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) |
2912 | { | 2916 | { |
2913 | struct inode *inode = old_dentry->d_inode; | 2917 | struct inode *inode = old_dentry->d_inode; |
2918 | unsigned max_links = dir->i_sb->s_max_links; | ||
2914 | int error; | 2919 | int error; |
2915 | 2920 | ||
2916 | if (!inode) | 2921 | if (!inode) |
@@ -2941,6 +2946,8 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de | |||
2941 | /* Make sure we don't allow creating hardlink to an unlinked file */ | 2946 | /* Make sure we don't allow creating hardlink to an unlinked file */ |
2942 | if (inode->i_nlink == 0) | 2947 | if (inode->i_nlink == 0) |
2943 | error = -ENOENT; | 2948 | error = -ENOENT; |
2949 | else if (max_links && inode->i_nlink >= max_links) | ||
2950 | error = -EMLINK; | ||
2944 | else | 2951 | else |
2945 | error = dir->i_op->link(old_dentry, dir, new_dentry); | 2952 | error = dir->i_op->link(old_dentry, dir, new_dentry); |
2946 | mutex_unlock(&inode->i_mutex); | 2953 | mutex_unlock(&inode->i_mutex); |
@@ -3050,6 +3057,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, | |||
3050 | { | 3057 | { |
3051 | int error = 0; | 3058 | int error = 0; |
3052 | struct inode *target = new_dentry->d_inode; | 3059 | struct inode *target = new_dentry->d_inode; |
3060 | unsigned max_links = new_dir->i_sb->s_max_links; | ||
3053 | 3061 | ||
3054 | /* | 3062 | /* |
3055 | * If we are going to change the parent - check write permissions, | 3063 | * If we are going to change the parent - check write permissions, |
@@ -3073,6 +3081,11 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, | |||
3073 | if (d_mountpoint(old_dentry) || d_mountpoint(new_dentry)) | 3081 | if (d_mountpoint(old_dentry) || d_mountpoint(new_dentry)) |
3074 | goto out; | 3082 | goto out; |
3075 | 3083 | ||
3084 | error = -EMLINK; | ||
3085 | if (max_links && !target && new_dir != old_dir && | ||
3086 | new_dir->i_nlink >= max_links) | ||
3087 | goto out; | ||
3088 | |||
3076 | if (target) | 3089 | if (target) |
3077 | shrink_dcache_parent(new_dentry); | 3090 | shrink_dcache_parent(new_dentry); |
3078 | error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); | 3091 | error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); |