diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2015-05-09 16:54:49 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-07-21 13:10:00 -0400 |
commit | c2f633b99857d27333de18f53d123a180672c52b (patch) | |
tree | 5df2d42d37538cd7c1abed60c471d75fdd320e13 /fs | |
parent | 5cf9896dc5c72a6c68c36140568b755f697f7760 (diff) |
fs: Add helper functions for permanently empty directories.
commit fbabfd0f4ee2e8847bf56edf481249ad1bb8c44d upstream.
To ensure it is safe to mount proc and sysfs I need to check if
filesystems that are mounted on top of them are mounted on truly empty
directories. Given that some directories can gain entries over time,
knowing that a directory is empty right now is insufficient.
Therefore add supporting infrastructure for permantently empty
directories that proc and sysfs can use when they create mount points
for filesystems and fs_fully_visible can use to test for permanently
empty directories to ensure that nothing will be gained by mounting a
fresh copy of proc or sysfs.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/libfs.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/fs/libfs.c b/fs/libfs.c index cb1fb4b9b637..02813592e121 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
@@ -1093,3 +1093,99 @@ simple_nosetlease(struct file *filp, long arg, struct file_lock **flp, | |||
1093 | return -EINVAL; | 1093 | return -EINVAL; |
1094 | } | 1094 | } |
1095 | EXPORT_SYMBOL(simple_nosetlease); | 1095 | EXPORT_SYMBOL(simple_nosetlease); |
1096 | |||
1097 | |||
1098 | /* | ||
1099 | * Operations for a permanently empty directory. | ||
1100 | */ | ||
1101 | static struct dentry *empty_dir_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) | ||
1102 | { | ||
1103 | return ERR_PTR(-ENOENT); | ||
1104 | } | ||
1105 | |||
1106 | static int empty_dir_getattr(struct vfsmount *mnt, struct dentry *dentry, | ||
1107 | struct kstat *stat) | ||
1108 | { | ||
1109 | struct inode *inode = d_inode(dentry); | ||
1110 | generic_fillattr(inode, stat); | ||
1111 | return 0; | ||
1112 | } | ||
1113 | |||
1114 | static int empty_dir_setattr(struct dentry *dentry, struct iattr *attr) | ||
1115 | { | ||
1116 | return -EPERM; | ||
1117 | } | ||
1118 | |||
1119 | static int empty_dir_setxattr(struct dentry *dentry, const char *name, | ||
1120 | const void *value, size_t size, int flags) | ||
1121 | { | ||
1122 | return -EOPNOTSUPP; | ||
1123 | } | ||
1124 | |||
1125 | static ssize_t empty_dir_getxattr(struct dentry *dentry, const char *name, | ||
1126 | void *value, size_t size) | ||
1127 | { | ||
1128 | return -EOPNOTSUPP; | ||
1129 | } | ||
1130 | |||
1131 | static int empty_dir_removexattr(struct dentry *dentry, const char *name) | ||
1132 | { | ||
1133 | return -EOPNOTSUPP; | ||
1134 | } | ||
1135 | |||
1136 | static ssize_t empty_dir_listxattr(struct dentry *dentry, char *list, size_t size) | ||
1137 | { | ||
1138 | return -EOPNOTSUPP; | ||
1139 | } | ||
1140 | |||
1141 | static const struct inode_operations empty_dir_inode_operations = { | ||
1142 | .lookup = empty_dir_lookup, | ||
1143 | .permission = generic_permission, | ||
1144 | .setattr = empty_dir_setattr, | ||
1145 | .getattr = empty_dir_getattr, | ||
1146 | .setxattr = empty_dir_setxattr, | ||
1147 | .getxattr = empty_dir_getxattr, | ||
1148 | .removexattr = empty_dir_removexattr, | ||
1149 | .listxattr = empty_dir_listxattr, | ||
1150 | }; | ||
1151 | |||
1152 | static loff_t empty_dir_llseek(struct file *file, loff_t offset, int whence) | ||
1153 | { | ||
1154 | /* An empty directory has two entries . and .. at offsets 0 and 1 */ | ||
1155 | return generic_file_llseek_size(file, offset, whence, 2, 2); | ||
1156 | } | ||
1157 | |||
1158 | static int empty_dir_readdir(struct file *file, struct dir_context *ctx) | ||
1159 | { | ||
1160 | dir_emit_dots(file, ctx); | ||
1161 | return 0; | ||
1162 | } | ||
1163 | |||
1164 | static const struct file_operations empty_dir_operations = { | ||
1165 | .llseek = empty_dir_llseek, | ||
1166 | .read = generic_read_dir, | ||
1167 | .iterate = empty_dir_readdir, | ||
1168 | .fsync = noop_fsync, | ||
1169 | }; | ||
1170 | |||
1171 | |||
1172 | void make_empty_dir_inode(struct inode *inode) | ||
1173 | { | ||
1174 | set_nlink(inode, 2); | ||
1175 | inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; | ||
1176 | inode->i_uid = GLOBAL_ROOT_UID; | ||
1177 | inode->i_gid = GLOBAL_ROOT_GID; | ||
1178 | inode->i_rdev = 0; | ||
1179 | inode->i_size = 2; | ||
1180 | inode->i_blkbits = PAGE_SHIFT; | ||
1181 | inode->i_blocks = 0; | ||
1182 | |||
1183 | inode->i_op = &empty_dir_inode_operations; | ||
1184 | inode->i_fop = &empty_dir_operations; | ||
1185 | } | ||
1186 | |||
1187 | bool is_empty_dir_inode(struct inode *inode) | ||
1188 | { | ||
1189 | return (inode->i_fop == &empty_dir_operations) && | ||
1190 | (inode->i_op == &empty_dir_inode_operations); | ||
1191 | } | ||