linux/fs/coda/dir.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3/*
   4 * Directory operations for Coda filesystem
   5 * Original version: (C) 1996 P. Braam and M. Callahan
   6 * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
   7 * 
   8 * Carnegie Mellon encourages users to contribute improvements to
   9 * 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 user_namespace *mnt_userns, 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_MTIME
 107        /* invalidate the directory cnode's attributes so we refetch the
 108         * attributes from venus next time the inode is referenced */
 109        coda_flag_inode(dir, C_VATTR);
 110#else
 111        /* optimistically we can also act as if our nose bleeds. The
 112         * granularity of the mtime is coarse anyways so we might actually be
 113         * right most of the time. Note: we only do this for directories. */
 114        dir->i_mtime = dir->i_ctime = current_time(dir);
 115#endif
 116}
 117
 118/* we have to wrap inc_nlink/drop_nlink because sometimes userspace uses a
 119 * trick to fool GNU find's optimizations. If we can't be sure of the link
 120 * (because of volume mount points) we set i_nlink to 1 which forces find
 121 * to consider every child as a possible directory. We should also never
 122 * 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 user_namespace *mnt_userns, 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 user_namespace *mnt_userns, 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 user_namespace *mnt_userns,
 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 create
 249         * 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 user_namespace *mnt_userns, 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_dir_update_mtime(old_dir);
 321                        coda_dir_update_mtime(new_dir);
 322                        coda_flag_inode(d_inode(new_dentry), C_VATTR);
 323                } else {
 324                        coda_flag_inode(old_dir, C_VATTR);
 325                        coda_flag_inode(new_dir, C_VATTR);
 326                }
 327        }
 328        return error;
 329}
 330
 331static inline unsigned int CDT2DT(unsigned char cdt)
 332{
 333        unsigned int dt;
 334
 335        switch(cdt) {
 336        case CDT_UNKNOWN: dt = DT_UNKNOWN; break;
 337        case CDT_FIFO:    dt = DT_FIFO;    break;
 338        case CDT_CHR:     dt = DT_CHR;     break;
 339        case CDT_DIR:     dt = DT_DIR;     break;
 340        case CDT_BLK:     dt = DT_BLK;     break;
 341        case CDT_REG:     dt = DT_REG;     break;
 342        case CDT_LNK:     dt = DT_LNK;     break;
 343        case CDT_SOCK:    dt = DT_SOCK;    break;
 344        case CDT_WHT:     dt = DT_WHT;     break;
 345        default:          dt = DT_UNKNOWN; break;
 346        }
 347        return dt;
 348}
 349
 350/* support routines */
 351static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx)
 352{
 353        struct coda_file_info *cfi;
 354        struct coda_inode_info *cii;
 355        struct file *host_file;
 356        struct venus_dirent *vdir;
 357        unsigned long vdir_size = offsetof(struct venus_dirent, d_name);
 358        unsigned int type;
 359        struct qstr name;
 360        ino_t ino;
 361        int ret;
 362
 363        cfi = coda_ftoc(coda_file);
 364        host_file = cfi->cfi_container;
 365
 366        cii = ITOC(file_inode(coda_file));
 367
 368        vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
 369        if (!vdir) return -ENOMEM;
 370
 371        if (!dir_emit_dots(coda_file, ctx))
 372                goto out;
 373
 374        while (1) {
 375                loff_t pos = ctx->pos - 2;
 376
 377                /* read entries from the directory file */
 378                ret = kernel_read(host_file, vdir, sizeof(*vdir), &pos);
 379                if (ret < 0) {
 380                        pr_err("%s: read dir %s failed %d\n",
 381                               __func__, coda_f2s(&cii->c_fid), ret);
 382                        break;
 383                }
 384                if (ret == 0) break; /* end of directory file reached */
 385
 386                /* catch truncated reads */
 387                if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
 388                        pr_err("%s: short read on %s\n",
 389                               __func__, coda_f2s(&cii->c_fid));
 390                        ret = -EBADF;
 391                        break;
 392                }
 393                /* validate whether the directory file actually makes sense */
 394                if (vdir->d_reclen < vdir_size + vdir->d_namlen) {
 395                        pr_err("%s: invalid dir %s\n",
 396                               __func__, coda_f2s(&cii->c_fid));
 397                        ret = -EBADF;
 398                        break;
 399                }
 400
 401                name.len = vdir->d_namlen;
 402                name.name = vdir->d_name;
 403
 404                /* Make sure we skip '.' and '..', we already got those */
 405                if (name.name[0] == '.' && (name.len == 1 ||
 406                    (name.name[1] == '.' && name.len == 2)))
 407                        vdir->d_fileno = name.len = 0;
 408
 409                /* skip null entries */
 410                if (vdir->d_fileno && name.len) {
 411                        ino = vdir->d_fileno;
 412                        type = CDT2DT(vdir->d_type);
 413                        if (!dir_emit(ctx, name.name, name.len, ino, type))
 414                                break;
 415                }
 416                /* we'll always have progress because d_reclen is unsigned and
 417                 * we've already established it is non-zero. */
 418                ctx->pos += vdir->d_reclen;
 419        }
 420out:
 421        kfree(vdir);
 422        return 0;
 423}
 424
 425/* file operations for directories */
 426static int coda_readdir(struct file *coda_file, struct dir_context *ctx)
 427{
 428        struct coda_file_info *cfi;
 429        struct file *host_file;
 430        int ret;
 431
 432        cfi = coda_ftoc(coda_file);
 433        host_file = cfi->cfi_container;
 434
 435        if (host_file->f_op->iterate || host_file->f_op->iterate_shared) {
 436                struct inode *host_inode = file_inode(host_file);
 437                ret = -ENOENT;
 438                if (!IS_DEADDIR(host_inode)) {
 439                        if (host_file->f_op->iterate_shared) {
 440                                inode_lock_shared(host_inode);
 441                                ret = host_file->f_op->iterate_shared(host_file, ctx);
 442                                file_accessed(host_file);
 443                                inode_unlock_shared(host_inode);
 444                        } else {
 445                                inode_lock(host_inode);
 446                                ret = host_file->f_op->iterate(host_file, ctx);
 447                                file_accessed(host_file);
 448                                inode_unlock(host_inode);
 449                        }
 450                }
 451                return ret;
 452        }
 453        /* Venus: we must read Venus dirents from a file */
 454        return coda_venus_readdir(coda_file, ctx);
 455}
 456
 457/* called when a cache lookup succeeds */
 458static int coda_dentry_revalidate(struct dentry *de, unsigned int flags)
 459{
 460        struct inode *inode;
 461        struct coda_inode_info *cii;
 462
 463        if (flags & LOOKUP_RCU)
 464                return -ECHILD;
 465
 466        inode = d_inode(de);
 467        if (!inode || is_root_inode(inode))
 468                goto out;
 469        if (is_bad_inode(inode))
 470                goto bad;
 471
 472        cii = ITOC(d_inode(de));
 473        if (!(cii->c_flags & (C_PURGE | C_FLUSH)))
 474                goto out;
 475
 476        shrink_dcache_parent(de);
 477
 478        /* propagate for a flush */
 479        if (cii->c_flags & C_FLUSH) 
 480                coda_flag_inode_children(inode, C_FLUSH);
 481
 482        if (d_count(de) > 1)
 483                /* pretend it's valid, but don't change the flags */
 484                goto out;
 485
 486        /* clear the flags. */
 487        spin_lock(&cii->c_lock);
 488        cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
 489        spin_unlock(&cii->c_lock);
 490bad:
 491        return 0;
 492out:
 493        return 1;
 494}
 495
 496/*
 497 * This is the callback from dput() when d_count is going to 0.
 498 * We use this to unhash dentries with bad inodes.
 499 */
 500static int coda_dentry_delete(const struct dentry * dentry)
 501{
 502        int flags;
 503
 504        if (d_really_is_negative(dentry)) 
 505                return 0;
 506
 507        flags = (ITOC(d_inode(dentry))->c_flags) & C_PURGE;
 508        if (is_bad_inode(d_inode(dentry)) || flags) {
 509                return 1;
 510        }
 511        return 0;
 512}
 513
 514
 515
 516/*
 517 * This is called when we want to check if the inode has
 518 * changed on the server.  Coda makes this easy since the
 519 * cache manager Venus issues a downcall to the kernel when this 
 520 * happens 
 521 */
 522int coda_revalidate_inode(struct inode *inode)
 523{
 524        struct coda_vattr attr;
 525        int error;
 526        int old_mode;
 527        ino_t old_ino;
 528        struct coda_inode_info *cii = ITOC(inode);
 529
 530        if (!cii->c_flags)
 531                return 0;
 532
 533        if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) {
 534                error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
 535                if (error)
 536                        return -EIO;
 537
 538                /* this inode may be lost if:
 539                   - it's ino changed 
 540                   - type changes must be permitted for repair and
 541                   missing mount points.
 542                */
 543                old_mode = inode->i_mode;
 544                old_ino = inode->i_ino;
 545                coda_vattr_to_iattr(inode, &attr);
 546
 547                if ((old_mode & S_IFMT) != (inode->i_mode & S_IFMT)) {
 548                        pr_warn("inode %ld, fid %s changed type!\n",
 549                                inode->i_ino, coda_f2s(&(cii->c_fid)));
 550                }
 551
 552                /* the following can happen when a local fid is replaced 
 553                   with a global one, here we lose and declare the inode bad */
 554                if (inode->i_ino != old_ino)
 555                        return -EIO;
 556                
 557                coda_flag_inode_children(inode, C_FLUSH);
 558
 559                spin_lock(&cii->c_lock);
 560                cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
 561                spin_unlock(&cii->c_lock);
 562        }
 563        return 0;
 564}
 565
 566const struct dentry_operations coda_dentry_operations = {
 567        .d_revalidate   = coda_dentry_revalidate,
 568        .d_delete       = coda_dentry_delete,
 569};
 570
 571const struct inode_operations coda_dir_inode_operations = {
 572        .create         = coda_create,
 573        .lookup         = coda_lookup,
 574        .link           = coda_link,
 575        .unlink         = coda_unlink,
 576        .symlink        = coda_symlink,
 577        .mkdir          = coda_mkdir,
 578        .rmdir          = coda_rmdir,
 579        .mknod          = CODA_EIO_ERROR,
 580        .rename         = coda_rename,
 581        .permission     = coda_permission,
 582        .getattr        = coda_getattr,
 583        .setattr        = coda_setattr,
 584};
 585
 586const struct file_operations coda_dir_operations = {
 587        .llseek         = generic_file_llseek,
 588        .read           = generic_read_dir,
 589        .iterate        = coda_readdir,
 590        .open           = coda_open,
 591        .release        = coda_release,
 592        .fsync          = coda_fsync,
 593};
 594