aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2012-02-06 12:45:27 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2012-03-20 21:29:32 -0400
commit8de52778798fe39660a8d6b26f290e0c93202761 (patch)
tree56384beb7863c1f338f2b66b509bf58eea5a99c2 /fs/namei.c
parentc16fa4f2ad19908a47c63d8fa436a1178438c7e7 (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.c13
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
2569int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) 2569int 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
2911int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) 2915int 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);