590 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/*4 * Directory operations for Coda filesystem5 * Original version: (C) 1996 P. Braam and M. Callahan6 * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University7 * 8 * Carnegie Mellon encourages users to contribute improvements to9 * the Coda project. Contact Peter Braam (coda@cs.cmu.edu).10 */11 12#include <linux/types.h>13#include <linux/kernel.h>14#include <linux/time.h>15#include <linux/fs.h>16#include <linux/slab.h>17#include <linux/file.h>18#include <linux/stat.h>19#include <linux/errno.h>20#include <linux/string.h>21#include <linux/spinlock.h>22#include <linux/namei.h>23#include <linux/uaccess.h>24 25#include <linux/coda.h>26#include "coda_psdev.h"27#include "coda_linux.h"28#include "coda_cache.h"29 30#include "coda_int.h"31 32/* same as fs/bad_inode.c */33static int coda_return_EIO(void)34{35 return -EIO;36}37#define CODA_EIO_ERROR ((void *) (coda_return_EIO))38 39/* inode operations for directories */40/* access routines: lookup, readlink, permission */41static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, unsigned int flags)42{43 struct super_block *sb = dir->i_sb;44 const char *name = entry->d_name.name;45 size_t length = entry->d_name.len;46 struct inode *inode;47 int type = 0;48 49 if (length > CODA_MAXNAMLEN) {50 pr_err("name too long: lookup, %s %zu\n",51 coda_i2s(dir), length);52 return ERR_PTR(-ENAMETOOLONG);53 }54 55 /* control object, create inode on the fly */56 if (is_root_inode(dir) && coda_iscontrol(name, length)) {57 inode = coda_cnode_makectl(sb);58 type = CODA_NOCACHE;59 } else {60 struct CodaFid fid = { { 0, } };61 int error = venus_lookup(sb, coda_i2f(dir), name, length,62 &type, &fid);63 inode = !error ? coda_cnode_make(&fid, sb) : ERR_PTR(error);64 }65 66 if (!IS_ERR(inode) && (type & CODA_NOCACHE))67 coda_flag_inode(inode, C_VATTR | C_PURGE);68 69 if (inode == ERR_PTR(-ENOENT))70 inode = NULL;71 72 return d_splice_alias(inode, entry);73}74 75 76int coda_permission(struct mnt_idmap *idmap, struct inode *inode,77 int mask)78{79 int error;80 81 if (mask & MAY_NOT_BLOCK)82 return -ECHILD;83 84 mask &= MAY_READ | MAY_WRITE | MAY_EXEC;85 86 if (!mask)87 return 0;88 89 if ((mask & MAY_EXEC) && !execute_ok(inode))90 return -EACCES;91 92 if (coda_cache_check(inode, mask))93 return 0;94 95 error = venus_access(inode->i_sb, coda_i2f(inode), mask);96 97 if (!error)98 coda_cache_enter(inode, mask);99 100 return error;101}102 103 104static inline void coda_dir_update_mtime(struct inode *dir)105{106#ifdef REQUERY_VENUS_FOR_MTIME107 /* invalidate the directory cnode's attributes so we refetch the108 * attributes from venus next time the inode is referenced */109 coda_flag_inode(dir, C_VATTR);110#else111 /* optimistically we can also act as if our nose bleeds. The112 * granularity of the mtime is coarse anyways so we might actually be113 * right most of the time. Note: we only do this for directories. */114 inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));115#endif116}117 118/* we have to wrap inc_nlink/drop_nlink because sometimes userspace uses a119 * trick to fool GNU find's optimizations. If we can't be sure of the link120 * (because of volume mount points) we set i_nlink to 1 which forces find121 * to consider every child as a possible directory. We should also never122 * see an increment or decrement for deleted directories where i_nlink == 0 */123static inline void coda_dir_inc_nlink(struct inode *dir)124{125 if (dir->i_nlink >= 2)126 inc_nlink(dir);127}128 129static inline void coda_dir_drop_nlink(struct inode *dir)130{131 if (dir->i_nlink > 2)132 drop_nlink(dir);133}134 135/* creation routines: create, mknod, mkdir, link, symlink */136static int coda_create(struct mnt_idmap *idmap, struct inode *dir,137 struct dentry *de, umode_t mode, bool excl)138{139 int error;140 const char *name=de->d_name.name;141 int length=de->d_name.len;142 struct inode *inode;143 struct CodaFid newfid;144 struct coda_vattr attrs;145 146 if (is_root_inode(dir) && coda_iscontrol(name, length))147 return -EPERM;148 149 error = venus_create(dir->i_sb, coda_i2f(dir), name, length, 150 0, mode, &newfid, &attrs);151 if (error)152 goto err_out;153 154 inode = coda_iget(dir->i_sb, &newfid, &attrs);155 if (IS_ERR(inode)) {156 error = PTR_ERR(inode);157 goto err_out;158 }159 160 /* invalidate the directory cnode's attributes */161 coda_dir_update_mtime(dir);162 d_instantiate(de, inode);163 return 0;164err_out:165 d_drop(de);166 return error;167}168 169static int coda_mkdir(struct mnt_idmap *idmap, struct inode *dir,170 struct dentry *de, umode_t mode)171{172 struct inode *inode;173 struct coda_vattr attrs;174 const char *name = de->d_name.name;175 int len = de->d_name.len;176 int error;177 struct CodaFid newfid;178 179 if (is_root_inode(dir) && coda_iscontrol(name, len))180 return -EPERM;181 182 attrs.va_mode = mode;183 error = venus_mkdir(dir->i_sb, coda_i2f(dir), 184 name, len, &newfid, &attrs);185 if (error)186 goto err_out;187 188 inode = coda_iget(dir->i_sb, &newfid, &attrs);189 if (IS_ERR(inode)) {190 error = PTR_ERR(inode);191 goto err_out;192 }193 194 /* invalidate the directory cnode's attributes */195 coda_dir_inc_nlink(dir);196 coda_dir_update_mtime(dir);197 d_instantiate(de, inode);198 return 0;199err_out:200 d_drop(de);201 return error;202}203 204/* try to make de an entry in dir_inodde linked to source_de */ 205static int coda_link(struct dentry *source_de, struct inode *dir_inode, 206 struct dentry *de)207{208 struct inode *inode = d_inode(source_de);209 const char * name = de->d_name.name;210 int len = de->d_name.len;211 int error;212 213 if (is_root_inode(dir_inode) && coda_iscontrol(name, len))214 return -EPERM;215 216 error = venus_link(dir_inode->i_sb, coda_i2f(inode),217 coda_i2f(dir_inode), (const char *)name, len);218 if (error) {219 d_drop(de);220 return error;221 }222 223 coda_dir_update_mtime(dir_inode);224 ihold(inode);225 d_instantiate(de, inode);226 inc_nlink(inode);227 return 0;228}229 230 231static int coda_symlink(struct mnt_idmap *idmap,232 struct inode *dir_inode, struct dentry *de,233 const char *symname)234{235 const char *name = de->d_name.name;236 int len = de->d_name.len;237 int symlen;238 int error;239 240 if (is_root_inode(dir_inode) && coda_iscontrol(name, len))241 return -EPERM;242 243 symlen = strlen(symname);244 if (symlen > CODA_MAXPATHLEN)245 return -ENAMETOOLONG;246 247 /*248 * This entry is now negative. Since we do not create249 * an inode for the entry we have to drop it.250 */251 d_drop(de);252 error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len,253 symname, symlen);254 255 /* mtime is no good anymore */256 if (!error)257 coda_dir_update_mtime(dir_inode);258 259 return error;260}261 262/* destruction routines: unlink, rmdir */263static int coda_unlink(struct inode *dir, struct dentry *de)264{265 int error;266 const char *name = de->d_name.name;267 int len = de->d_name.len;268 269 error = venus_remove(dir->i_sb, coda_i2f(dir), name, len);270 if (error)271 return error;272 273 coda_dir_update_mtime(dir);274 drop_nlink(d_inode(de));275 return 0;276}277 278static int coda_rmdir(struct inode *dir, struct dentry *de)279{280 const char *name = de->d_name.name;281 int len = de->d_name.len;282 int error;283 284 error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len);285 if (!error) {286 /* VFS may delete the child */287 if (d_really_is_positive(de))288 clear_nlink(d_inode(de));289 290 /* fix the link count of the parent */291 coda_dir_drop_nlink(dir);292 coda_dir_update_mtime(dir);293 }294 return error;295}296 297/* rename */298static int coda_rename(struct mnt_idmap *idmap, struct inode *old_dir,299 struct dentry *old_dentry, struct inode *new_dir,300 struct dentry *new_dentry, unsigned int flags)301{302 const char *old_name = old_dentry->d_name.name;303 const char *new_name = new_dentry->d_name.name;304 int old_length = old_dentry->d_name.len;305 int new_length = new_dentry->d_name.len;306 int error;307 308 if (flags)309 return -EINVAL;310 311 error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),312 coda_i2f(new_dir), old_length, new_length,313 (const char *) old_name, (const char *)new_name);314 if (!error) {315 if (d_really_is_positive(new_dentry)) {316 if (d_is_dir(new_dentry)) {317 coda_dir_drop_nlink(old_dir);318 coda_dir_inc_nlink(new_dir);319 }320 coda_flag_inode(d_inode(new_dentry), C_VATTR);321 }322 coda_dir_update_mtime(old_dir);323 coda_dir_update_mtime(new_dir);324 }325 return error;326}327 328static inline unsigned int CDT2DT(unsigned char cdt)329{330 unsigned int dt;331 332 switch(cdt) {333 case CDT_UNKNOWN: dt = DT_UNKNOWN; break;334 case CDT_FIFO: dt = DT_FIFO; break;335 case CDT_CHR: dt = DT_CHR; break;336 case CDT_DIR: dt = DT_DIR; break;337 case CDT_BLK: dt = DT_BLK; break;338 case CDT_REG: dt = DT_REG; break;339 case CDT_LNK: dt = DT_LNK; break;340 case CDT_SOCK: dt = DT_SOCK; break;341 case CDT_WHT: dt = DT_WHT; break;342 default: dt = DT_UNKNOWN; break;343 }344 return dt;345}346 347/* support routines */348static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx)349{350 struct coda_file_info *cfi;351 struct coda_inode_info *cii;352 struct file *host_file;353 struct venus_dirent *vdir;354 unsigned long vdir_size = offsetof(struct venus_dirent, d_name);355 unsigned int type;356 struct qstr name;357 ino_t ino;358 int ret;359 360 cfi = coda_ftoc(coda_file);361 host_file = cfi->cfi_container;362 363 cii = ITOC(file_inode(coda_file));364 365 vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);366 if (!vdir) return -ENOMEM;367 368 if (!dir_emit_dots(coda_file, ctx))369 goto out;370 371 while (1) {372 loff_t pos = ctx->pos - 2;373 374 /* read entries from the directory file */375 ret = kernel_read(host_file, vdir, sizeof(*vdir), &pos);376 if (ret < 0) {377 pr_err("%s: read dir %s failed %d\n",378 __func__, coda_f2s(&cii->c_fid), ret);379 break;380 }381 if (ret == 0) break; /* end of directory file reached */382 383 /* catch truncated reads */384 if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {385 pr_err("%s: short read on %s\n",386 __func__, coda_f2s(&cii->c_fid));387 ret = -EBADF;388 break;389 }390 /* validate whether the directory file actually makes sense */391 if (vdir->d_reclen < vdir_size + vdir->d_namlen) {392 pr_err("%s: invalid dir %s\n",393 __func__, coda_f2s(&cii->c_fid));394 ret = -EBADF;395 break;396 }397 398 name.len = vdir->d_namlen;399 name.name = vdir->d_name;400 401 /* Make sure we skip '.' and '..', we already got those */402 if (name.name[0] == '.' && (name.len == 1 ||403 (name.name[1] == '.' && name.len == 2)))404 vdir->d_fileno = name.len = 0;405 406 /* skip null entries */407 if (vdir->d_fileno && name.len) {408 ino = vdir->d_fileno;409 type = CDT2DT(vdir->d_type);410 if (!dir_emit(ctx, name.name, name.len, ino, type))411 break;412 }413 /* we'll always have progress because d_reclen is unsigned and414 * we've already established it is non-zero. */415 ctx->pos += vdir->d_reclen;416 }417out:418 kfree(vdir);419 return 0;420}421 422/* file operations for directories */423static int coda_readdir(struct file *coda_file, struct dir_context *ctx)424{425 struct coda_file_info *cfi;426 struct file *host_file;427 int ret;428 429 cfi = coda_ftoc(coda_file);430 host_file = cfi->cfi_container;431 432 if (host_file->f_op->iterate_shared) {433 struct inode *host_inode = file_inode(host_file);434 ret = -ENOENT;435 if (!IS_DEADDIR(host_inode)) {436 inode_lock_shared(host_inode);437 ret = host_file->f_op->iterate_shared(host_file, ctx);438 file_accessed(host_file);439 inode_unlock_shared(host_inode);440 }441 return ret;442 }443 /* Venus: we must read Venus dirents from a file */444 return coda_venus_readdir(coda_file, ctx);445}446 447/* called when a cache lookup succeeds */448static int coda_dentry_revalidate(struct dentry *de, unsigned int flags)449{450 struct inode *inode;451 struct coda_inode_info *cii;452 453 if (flags & LOOKUP_RCU)454 return -ECHILD;455 456 inode = d_inode(de);457 if (!inode || is_root_inode(inode))458 goto out;459 if (is_bad_inode(inode))460 goto bad;461 462 cii = ITOC(d_inode(de));463 if (!(cii->c_flags & (C_PURGE | C_FLUSH)))464 goto out;465 466 shrink_dcache_parent(de);467 468 /* propagate for a flush */469 if (cii->c_flags & C_FLUSH) 470 coda_flag_inode_children(inode, C_FLUSH);471 472 if (d_count(de) > 1)473 /* pretend it's valid, but don't change the flags */474 goto out;475 476 /* clear the flags. */477 spin_lock(&cii->c_lock);478 cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);479 spin_unlock(&cii->c_lock);480bad:481 return 0;482out:483 return 1;484}485 486/*487 * This is the callback from dput() when d_count is going to 0.488 * We use this to unhash dentries with bad inodes.489 */490static int coda_dentry_delete(const struct dentry * dentry)491{492 struct inode *inode;493 struct coda_inode_info *cii;494 495 if (d_really_is_negative(dentry)) 496 return 0;497 498 inode = d_inode(dentry);499 if (!inode || is_bad_inode(inode))500 return 1;501 502 cii = ITOC(inode);503 if (cii->c_flags & C_PURGE)504 return 1;505 506 return 0;507}508 509 510 511/*512 * This is called when we want to check if the inode has513 * changed on the server. Coda makes this easy since the514 * cache manager Venus issues a downcall to the kernel when this 515 * happens 516 */517int coda_revalidate_inode(struct inode *inode)518{519 struct coda_vattr attr;520 int error;521 int old_mode;522 ino_t old_ino;523 struct coda_inode_info *cii = ITOC(inode);524 525 if (!cii->c_flags)526 return 0;527 528 if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) {529 error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);530 if (error)531 return -EIO;532 533 /* this inode may be lost if:534 - it's ino changed 535 - type changes must be permitted for repair and536 missing mount points.537 */538 old_mode = inode->i_mode;539 old_ino = inode->i_ino;540 coda_vattr_to_iattr(inode, &attr);541 542 if ((old_mode & S_IFMT) != (inode->i_mode & S_IFMT)) {543 pr_warn("inode %ld, fid %s changed type!\n",544 inode->i_ino, coda_f2s(&(cii->c_fid)));545 }546 547 /* the following can happen when a local fid is replaced 548 with a global one, here we lose and declare the inode bad */549 if (inode->i_ino != old_ino)550 return -EIO;551 552 coda_flag_inode_children(inode, C_FLUSH);553 554 spin_lock(&cii->c_lock);555 cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);556 spin_unlock(&cii->c_lock);557 }558 return 0;559}560 561const struct dentry_operations coda_dentry_operations = {562 .d_revalidate = coda_dentry_revalidate,563 .d_delete = coda_dentry_delete,564};565 566const struct inode_operations coda_dir_inode_operations = {567 .create = coda_create,568 .lookup = coda_lookup,569 .link = coda_link,570 .unlink = coda_unlink,571 .symlink = coda_symlink,572 .mkdir = coda_mkdir,573 .rmdir = coda_rmdir,574 .mknod = CODA_EIO_ERROR,575 .rename = coda_rename,576 .permission = coda_permission,577 .getattr = coda_getattr,578 .setattr = coda_setattr,579};580 581WRAP_DIR_ITER(coda_readdir) // FIXME!582const struct file_operations coda_dir_operations = {583 .llseek = generic_file_llseek,584 .read = generic_read_dir,585 .iterate_shared = shared_coda_readdir,586 .open = coda_open,587 .release = coda_release,588 .fsync = coda_fsync,589};590