|
1 |
| -/* dir.c: AFS dynamic root handling |
| 1 | +/* AFS dynamic root handling |
2 | 2 | *
|
3 | 3 | * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
|
4 | 4 | * Written by David Howells ([email protected])
|
@@ -207,3 +207,125 @@ const struct dentry_operations afs_dynroot_dentry_operations = {
|
207 | 207 | .d_release = afs_d_release,
|
208 | 208 | .d_automount = afs_d_automount,
|
209 | 209 | };
|
| 210 | + |
| 211 | +/* |
| 212 | + * Create a manually added cell mount directory. |
| 213 | + * - The caller must hold net->proc_cells_lock |
| 214 | + */ |
| 215 | +int afs_dynroot_mkdir(struct afs_net *net, struct afs_cell *cell) |
| 216 | +{ |
| 217 | + struct super_block *sb = net->dynroot_sb; |
| 218 | + struct dentry *root, *subdir; |
| 219 | + int ret; |
| 220 | + |
| 221 | + if (!sb || atomic_read(&sb->s_active) == 0) |
| 222 | + return 0; |
| 223 | + |
| 224 | + /* Let the ->lookup op do the creation */ |
| 225 | + root = sb->s_root; |
| 226 | + inode_lock(root->d_inode); |
| 227 | + subdir = lookup_one_len(cell->name, root, cell->name_len); |
| 228 | + if (IS_ERR(subdir)) { |
| 229 | + ret = PTR_ERR(subdir); |
| 230 | + goto unlock; |
| 231 | + } |
| 232 | + |
| 233 | + /* Note that we're retaining an extra ref on the dentry */ |
| 234 | + subdir->d_fsdata = (void *)1UL; |
| 235 | + ret = 0; |
| 236 | +unlock: |
| 237 | + inode_unlock(root->d_inode); |
| 238 | + return ret; |
| 239 | +} |
| 240 | + |
| 241 | +/* |
| 242 | + * Remove a manually added cell mount directory. |
| 243 | + * - The caller must hold net->proc_cells_lock |
| 244 | + */ |
| 245 | +void afs_dynroot_rmdir(struct afs_net *net, struct afs_cell *cell) |
| 246 | +{ |
| 247 | + struct super_block *sb = net->dynroot_sb; |
| 248 | + struct dentry *root, *subdir; |
| 249 | + |
| 250 | + if (!sb || atomic_read(&sb->s_active) == 0) |
| 251 | + return; |
| 252 | + |
| 253 | + root = sb->s_root; |
| 254 | + inode_lock(root->d_inode); |
| 255 | + |
| 256 | + /* Don't want to trigger a lookup call, which will re-add the cell */ |
| 257 | + subdir = try_lookup_one_len(cell->name, root, cell->name_len); |
| 258 | + if (IS_ERR_OR_NULL(subdir)) { |
| 259 | + _debug("lookup %ld", PTR_ERR(subdir)); |
| 260 | + goto no_dentry; |
| 261 | + } |
| 262 | + |
| 263 | + _debug("rmdir %pd %u", subdir, d_count(subdir)); |
| 264 | + |
| 265 | + if (subdir->d_fsdata) { |
| 266 | + _debug("unpin %u", d_count(subdir)); |
| 267 | + subdir->d_fsdata = NULL; |
| 268 | + dput(subdir); |
| 269 | + } |
| 270 | + dput(subdir); |
| 271 | +no_dentry: |
| 272 | + inode_unlock(root->d_inode); |
| 273 | + _leave(""); |
| 274 | +} |
| 275 | + |
| 276 | +/* |
| 277 | + * Populate a newly created dynamic root with cell names. |
| 278 | + */ |
| 279 | +int afs_dynroot_populate(struct super_block *sb) |
| 280 | +{ |
| 281 | + struct afs_cell *cell; |
| 282 | + struct afs_net *net = afs_sb2net(sb); |
| 283 | + int ret; |
| 284 | + |
| 285 | + if (mutex_lock_interruptible(&net->proc_cells_lock) < 0) |
| 286 | + return -ERESTARTSYS; |
| 287 | + |
| 288 | + net->dynroot_sb = sb; |
| 289 | + list_for_each_entry(cell, &net->proc_cells, proc_link) { |
| 290 | + ret = afs_dynroot_mkdir(net, cell); |
| 291 | + if (ret < 0) |
| 292 | + goto error; |
| 293 | + } |
| 294 | + |
| 295 | + ret = 0; |
| 296 | +out: |
| 297 | + mutex_unlock(&net->proc_cells_lock); |
| 298 | + return ret; |
| 299 | + |
| 300 | +error: |
| 301 | + net->dynroot_sb = NULL; |
| 302 | + goto out; |
| 303 | +} |
| 304 | + |
| 305 | +/* |
| 306 | + * When a dynamic root that's in the process of being destroyed, depopulate it |
| 307 | + * of pinned directories. |
| 308 | + */ |
| 309 | +void afs_dynroot_depopulate(struct super_block *sb) |
| 310 | +{ |
| 311 | + struct afs_net *net = afs_sb2net(sb); |
| 312 | + struct dentry *root = sb->s_root, *subdir, *tmp; |
| 313 | + |
| 314 | + /* Prevent more subdirs from being created */ |
| 315 | + mutex_lock(&net->proc_cells_lock); |
| 316 | + if (net->dynroot_sb == sb) |
| 317 | + net->dynroot_sb = NULL; |
| 318 | + mutex_unlock(&net->proc_cells_lock); |
| 319 | + |
| 320 | + inode_lock(root->d_inode); |
| 321 | + |
| 322 | + /* Remove all the pins for dirs created for manually added cells */ |
| 323 | + list_for_each_entry_safe(subdir, tmp, &root->d_subdirs, d_child) { |
| 324 | + if (subdir->d_fsdata) { |
| 325 | + subdir->d_fsdata = NULL; |
| 326 | + dput(subdir); |
| 327 | + } |
| 328 | + } |
| 329 | + |
| 330 | + inode_unlock(root->d_inode); |
| 331 | +} |
0 commit comments