1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds 31da177e4SLinus Torvalds /* 41da177e4SLinus Torvalds * Directory operations for Coda filesystem 51da177e4SLinus Torvalds * Original version: (C) 1996 P. Braam and M. Callahan 61da177e4SLinus Torvalds * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Carnegie Mellon encourages users to contribute improvements to 91da177e4SLinus Torvalds * the Coda project. Contact Peter Braam (coda@cs.cmu.edu). 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/types.h> 131da177e4SLinus Torvalds #include <linux/kernel.h> 141da177e4SLinus Torvalds #include <linux/time.h> 151da177e4SLinus Torvalds #include <linux/fs.h> 165a0e3ad6STejun Heo #include <linux/slab.h> 171da177e4SLinus Torvalds #include <linux/file.h> 181da177e4SLinus Torvalds #include <linux/stat.h> 191da177e4SLinus Torvalds #include <linux/errno.h> 201da177e4SLinus Torvalds #include <linux/string.h> 21b5ce1d83SYoshihisa Abe #include <linux/spinlock.h> 2234286d66SNick Piggin #include <linux/namei.h> 23834b46c3SFabian Frederick #include <linux/uaccess.h> 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #include <linux/coda.h> 268fc8b9dfSDavid Howells #include "coda_psdev.h" 2731a203dfSAl Viro #include "coda_linux.h" 2831a203dfSAl Viro #include "coda_cache.h" 291da177e4SLinus Torvalds 30c98d8cfbSAdrian Bunk #include "coda_int.h" 31c98d8cfbSAdrian Bunk 321da177e4SLinus Torvalds /* same as fs/bad_inode.c */ 331da177e4SLinus Torvalds static int coda_return_EIO(void) 341da177e4SLinus Torvalds { 351da177e4SLinus Torvalds return -EIO; 361da177e4SLinus Torvalds } 371da177e4SLinus Torvalds #define CODA_EIO_ERROR ((void *) (coda_return_EIO)) 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds /* inode operations for directories */ 401da177e4SLinus Torvalds /* access routines: lookup, readlink, permission */ 4100cd8dd3SAl Viro static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, unsigned int flags) 421da177e4SLinus Torvalds { 43f4947fbcSAl Viro struct super_block *sb = dir->i_sb; 441da177e4SLinus Torvalds const char *name = entry->d_name.name; 451da177e4SLinus Torvalds size_t length = entry->d_name.len; 46f4947fbcSAl Viro struct inode *inode; 47f4947fbcSAl Viro int type = 0; 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds if (length > CODA_MAXNAMLEN) { 509a05671dSJan Harkes pr_err("name too long: lookup, %s %zu\n", 519a05671dSJan Harkes coda_i2s(dir), length); 521da177e4SLinus Torvalds return ERR_PTR(-ENAMETOOLONG); 531da177e4SLinus Torvalds } 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds /* control object, create inode on the fly */ 56a7400222SAl Viro if (is_root_inode(dir) && coda_iscontrol(name, length)) { 57f4947fbcSAl Viro inode = coda_cnode_makectl(sb); 58ed36f723SJan Harkes type = CODA_NOCACHE; 59f4947fbcSAl Viro } else { 60f4947fbcSAl Viro struct CodaFid fid = { { 0, } }; 61f4947fbcSAl Viro int error = venus_lookup(sb, coda_i2f(dir), name, length, 62f4947fbcSAl Viro &type, &fid); 63f4947fbcSAl Viro inode = !error ? coda_cnode_make(&fid, sb) : ERR_PTR(error); 641da177e4SLinus Torvalds } 651da177e4SLinus Torvalds 66f4947fbcSAl Viro if (!IS_ERR(inode) && (type & CODA_NOCACHE)) 67ed36f723SJan Harkes coda_flag_inode(inode, C_VATTR | C_PURGE); 68ed36f723SJan Harkes 69f4947fbcSAl Viro if (inode == ERR_PTR(-ENOENT)) 70f4947fbcSAl Viro inode = NULL; 71f4947fbcSAl Viro 72ed36f723SJan Harkes return d_splice_alias(inode, entry); 731da177e4SLinus Torvalds } 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds 76549c7297SChristian Brauner int coda_permission(struct user_namespace *mnt_userns, struct inode *inode, 77549c7297SChristian Brauner int mask) 781da177e4SLinus Torvalds { 79f7cc02b8SYoshihisa Abe int error; 801da177e4SLinus Torvalds 8110556cb2SAl Viro if (mask & MAY_NOT_BLOCK) 82b74c79e9SNick Piggin return -ECHILD; 83b74c79e9SNick Piggin 84e6305c43SAl Viro mask &= MAY_READ | MAY_WRITE | MAY_EXEC; 85e6305c43SAl Viro 861da177e4SLinus Torvalds if (!mask) 871da177e4SLinus Torvalds return 0; 881da177e4SLinus Torvalds 89f696a365SMiklos Szeredi if ((mask & MAY_EXEC) && !execute_ok(inode)) 90f696a365SMiklos Szeredi return -EACCES; 91f696a365SMiklos Szeredi 921da177e4SLinus Torvalds if (coda_cache_check(inode, mask)) 93f7cc02b8SYoshihisa Abe return 0; 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds error = venus_access(inode->i_sb, coda_i2f(inode), mask); 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds if (!error) 981da177e4SLinus Torvalds coda_cache_enter(inode, mask); 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds return error; 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds 104d728900cSJan Harkes static inline void coda_dir_update_mtime(struct inode *dir) 1051da177e4SLinus Torvalds { 1061da177e4SLinus Torvalds #ifdef REQUERY_VENUS_FOR_MTIME 1071da177e4SLinus Torvalds /* invalidate the directory cnode's attributes so we refetch the 1081da177e4SLinus Torvalds * attributes from venus next time the inode is referenced */ 1091da177e4SLinus Torvalds coda_flag_inode(dir, C_VATTR); 1101da177e4SLinus Torvalds #else 1111da177e4SLinus Torvalds /* optimistically we can also act as if our nose bleeds. The 1121da177e4SLinus Torvalds * granularity of the mtime is coarse anyways so we might actually be 1131da177e4SLinus Torvalds * right most of the time. Note: we only do this for directories. */ 11402027d42SDeepa Dinamani dir->i_mtime = dir->i_ctime = current_time(dir); 1151da177e4SLinus Torvalds #endif 116d728900cSJan Harkes } 117d728900cSJan Harkes 118d728900cSJan Harkes /* we have to wrap inc_nlink/drop_nlink because sometimes userspace uses a 119d728900cSJan Harkes * trick to fool GNU find's optimizations. If we can't be sure of the link 120d728900cSJan Harkes * (because of volume mount points) we set i_nlink to 1 which forces find 121d728900cSJan Harkes * to consider every child as a possible directory. We should also never 122d728900cSJan Harkes * see an increment or decrement for deleted directories where i_nlink == 0 */ 123d728900cSJan Harkes static inline void coda_dir_inc_nlink(struct inode *dir) 124d728900cSJan Harkes { 125d728900cSJan Harkes if (dir->i_nlink >= 2) 126d728900cSJan Harkes inc_nlink(dir); 127d728900cSJan Harkes } 128d728900cSJan Harkes 129d728900cSJan Harkes static inline void coda_dir_drop_nlink(struct inode *dir) 130d728900cSJan Harkes { 131d728900cSJan Harkes if (dir->i_nlink > 2) 132d728900cSJan Harkes drop_nlink(dir); 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds /* creation routines: create, mknod, mkdir, link, symlink */ 1366c960e68SChristian Brauner static int coda_create(struct mnt_idmap *idmap, struct inode *dir, 137549c7297SChristian Brauner struct dentry *de, umode_t mode, bool excl) 1381da177e4SLinus Torvalds { 139f7cc02b8SYoshihisa Abe int error; 1401da177e4SLinus Torvalds const char *name=de->d_name.name; 1411da177e4SLinus Torvalds int length=de->d_name.len; 1421da177e4SLinus Torvalds struct inode *inode; 1431da177e4SLinus Torvalds struct CodaFid newfid; 1441da177e4SLinus Torvalds struct coda_vattr attrs; 1451da177e4SLinus Torvalds 146a7400222SAl Viro if (is_root_inode(dir) && coda_iscontrol(name, length)) 1471da177e4SLinus Torvalds return -EPERM; 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds error = venus_create(dir->i_sb, coda_i2f(dir), name, length, 1501da177e4SLinus Torvalds 0, mode, &newfid, &attrs); 151f7cc02b8SYoshihisa Abe if (error) 152f7cc02b8SYoshihisa Abe goto err_out; 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds inode = coda_iget(dir->i_sb, &newfid, &attrs); 1551da177e4SLinus Torvalds if (IS_ERR(inode)) { 156f7cc02b8SYoshihisa Abe error = PTR_ERR(inode); 157f7cc02b8SYoshihisa Abe goto err_out; 1581da177e4SLinus Torvalds } 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds /* invalidate the directory cnode's attributes */ 161d728900cSJan Harkes coda_dir_update_mtime(dir); 1621da177e4SLinus Torvalds d_instantiate(de, inode); 1631da177e4SLinus Torvalds return 0; 164f7cc02b8SYoshihisa Abe err_out: 165f7cc02b8SYoshihisa Abe d_drop(de); 166f7cc02b8SYoshihisa Abe return error; 1671da177e4SLinus Torvalds } 1681da177e4SLinus Torvalds 169c54bd91eSChristian Brauner static int coda_mkdir(struct mnt_idmap *idmap, struct inode *dir, 170549c7297SChristian Brauner struct dentry *de, umode_t mode) 1711da177e4SLinus Torvalds { 1721da177e4SLinus Torvalds struct inode *inode; 1731da177e4SLinus Torvalds struct coda_vattr attrs; 1741da177e4SLinus Torvalds const char *name = de->d_name.name; 1751da177e4SLinus Torvalds int len = de->d_name.len; 1761da177e4SLinus Torvalds int error; 1771da177e4SLinus Torvalds struct CodaFid newfid; 1781da177e4SLinus Torvalds 179a7400222SAl Viro if (is_root_inode(dir) && coda_iscontrol(name, len)) 1801da177e4SLinus Torvalds return -EPERM; 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds attrs.va_mode = mode; 1831da177e4SLinus Torvalds error = venus_mkdir(dir->i_sb, coda_i2f(dir), 1841da177e4SLinus Torvalds name, len, &newfid, &attrs); 185f7cc02b8SYoshihisa Abe if (error) 186f7cc02b8SYoshihisa Abe goto err_out; 1871da177e4SLinus Torvalds 1881da177e4SLinus Torvalds inode = coda_iget(dir->i_sb, &newfid, &attrs); 1891da177e4SLinus Torvalds if (IS_ERR(inode)) { 190f7cc02b8SYoshihisa Abe error = PTR_ERR(inode); 191f7cc02b8SYoshihisa Abe goto err_out; 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds /* invalidate the directory cnode's attributes */ 195d728900cSJan Harkes coda_dir_inc_nlink(dir); 196d728900cSJan Harkes coda_dir_update_mtime(dir); 1971da177e4SLinus Torvalds d_instantiate(de, inode); 1981da177e4SLinus Torvalds return 0; 199f7cc02b8SYoshihisa Abe err_out: 200f7cc02b8SYoshihisa Abe d_drop(de); 201f7cc02b8SYoshihisa Abe return error; 2021da177e4SLinus Torvalds } 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds /* try to make de an entry in dir_inodde linked to source_de */ 2051da177e4SLinus Torvalds static int coda_link(struct dentry *source_de, struct inode *dir_inode, 2061da177e4SLinus Torvalds struct dentry *de) 2071da177e4SLinus Torvalds { 2082b0143b5SDavid Howells struct inode *inode = d_inode(source_de); 2091da177e4SLinus Torvalds const char * name = de->d_name.name; 2101da177e4SLinus Torvalds int len = de->d_name.len; 2111da177e4SLinus Torvalds int error; 2121da177e4SLinus Torvalds 213a7400222SAl Viro if (is_root_inode(dir_inode) && coda_iscontrol(name, len)) 2141da177e4SLinus Torvalds return -EPERM; 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds error = venus_link(dir_inode->i_sb, coda_i2f(inode), 2171da177e4SLinus Torvalds coda_i2f(dir_inode), (const char *)name, len); 2181da177e4SLinus Torvalds if (error) { 2191da177e4SLinus Torvalds d_drop(de); 220f7cc02b8SYoshihisa Abe return error; 2211da177e4SLinus Torvalds } 2221da177e4SLinus Torvalds 223d728900cSJan Harkes coda_dir_update_mtime(dir_inode); 2247de9c6eeSAl Viro ihold(inode); 2251da177e4SLinus Torvalds d_instantiate(de, inode); 226d8c76e6fSDave Hansen inc_nlink(inode); 227f7cc02b8SYoshihisa Abe return 0; 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds 2317a77db95SChristian Brauner static int coda_symlink(struct mnt_idmap *idmap, 232549c7297SChristian Brauner struct inode *dir_inode, struct dentry *de, 2331da177e4SLinus Torvalds const char *symname) 2341da177e4SLinus Torvalds { 2351da177e4SLinus Torvalds const char *name = de->d_name.name; 2361da177e4SLinus Torvalds int len = de->d_name.len; 2371da177e4SLinus Torvalds int symlen; 238f7cc02b8SYoshihisa Abe int error; 2391da177e4SLinus Torvalds 240a7400222SAl Viro if (is_root_inode(dir_inode) && coda_iscontrol(name, len)) 2411da177e4SLinus Torvalds return -EPERM; 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds symlen = strlen(symname); 244f7cc02b8SYoshihisa Abe if (symlen > CODA_MAXPATHLEN) 2451da177e4SLinus Torvalds return -ENAMETOOLONG; 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds /* 2481da177e4SLinus Torvalds * This entry is now negative. Since we do not create 2491da177e4SLinus Torvalds * an inode for the entry we have to drop it. 2501da177e4SLinus Torvalds */ 2511da177e4SLinus Torvalds d_drop(de); 2521da177e4SLinus Torvalds error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len, 2531da177e4SLinus Torvalds symname, symlen); 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds /* mtime is no good anymore */ 2561da177e4SLinus Torvalds if (!error) 257d728900cSJan Harkes coda_dir_update_mtime(dir_inode); 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds return error; 2601da177e4SLinus Torvalds } 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds /* destruction routines: unlink, rmdir */ 2639fe76c76SHarvey Harrison static int coda_unlink(struct inode *dir, struct dentry *de) 2641da177e4SLinus Torvalds { 2651da177e4SLinus Torvalds int error; 2661da177e4SLinus Torvalds const char *name = de->d_name.name; 2671da177e4SLinus Torvalds int len = de->d_name.len; 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds error = venus_remove(dir->i_sb, coda_i2f(dir), name, len); 270f7cc02b8SYoshihisa Abe if (error) 2711da177e4SLinus Torvalds return error; 2721da177e4SLinus Torvalds 273d728900cSJan Harkes coda_dir_update_mtime(dir); 2742b0143b5SDavid Howells drop_nlink(d_inode(de)); 2751da177e4SLinus Torvalds return 0; 2761da177e4SLinus Torvalds } 2771da177e4SLinus Torvalds 2789fe76c76SHarvey Harrison static int coda_rmdir(struct inode *dir, struct dentry *de) 2791da177e4SLinus Torvalds { 2801da177e4SLinus Torvalds const char *name = de->d_name.name; 2811da177e4SLinus Torvalds int len = de->d_name.len; 2821da177e4SLinus Torvalds int error; 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len); 2858c6d2152SJan Harkes if (!error) { 2868c6d2152SJan Harkes /* VFS may delete the child */ 2872b0143b5SDavid Howells if (d_really_is_positive(de)) 2882b0143b5SDavid Howells clear_nlink(d_inode(de)); 2891da177e4SLinus Torvalds 2908c6d2152SJan Harkes /* fix the link count of the parent */ 291d728900cSJan Harkes coda_dir_drop_nlink(dir); 292d728900cSJan Harkes coda_dir_update_mtime(dir); 2938c6d2152SJan Harkes } 2948c6d2152SJan Harkes return error; 2951da177e4SLinus Torvalds } 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds /* rename */ 298*e18275aeSChristian Brauner static int coda_rename(struct mnt_idmap *idmap, struct inode *old_dir, 299549c7297SChristian Brauner struct dentry *old_dentry, struct inode *new_dir, 300549c7297SChristian Brauner struct dentry *new_dentry, unsigned int flags) 3011da177e4SLinus Torvalds { 3021da177e4SLinus Torvalds const char *old_name = old_dentry->d_name.name; 3031da177e4SLinus Torvalds const char *new_name = new_dentry->d_name.name; 3041da177e4SLinus Torvalds int old_length = old_dentry->d_name.len; 3051da177e4SLinus Torvalds int new_length = new_dentry->d_name.len; 3061da177e4SLinus Torvalds int error; 3071da177e4SLinus Torvalds 3081cd66c93SMiklos Szeredi if (flags) 3091cd66c93SMiklos Szeredi return -EINVAL; 3101cd66c93SMiklos Szeredi 3111da177e4SLinus Torvalds error = venus_rename(old_dir->i_sb, coda_i2f(old_dir), 3121da177e4SLinus Torvalds coda_i2f(new_dir), old_length, new_length, 3131da177e4SLinus Torvalds (const char *) old_name, (const char *)new_name); 3141da177e4SLinus Torvalds if (!error) { 3152b0143b5SDavid Howells if (d_really_is_positive(new_dentry)) { 316e36cb0b8SDavid Howells if (d_is_dir(new_dentry)) { 317d728900cSJan Harkes coda_dir_drop_nlink(old_dir); 318d728900cSJan Harkes coda_dir_inc_nlink(new_dir); 319d728900cSJan Harkes } 320b2e36228SJan Harkes coda_flag_inode(d_inode(new_dentry), C_VATTR); 321b2e36228SJan Harkes } 322d728900cSJan Harkes coda_dir_update_mtime(old_dir); 323d728900cSJan Harkes coda_dir_update_mtime(new_dir); 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds return error; 3261da177e4SLinus Torvalds } 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds static inline unsigned int CDT2DT(unsigned char cdt) 3291da177e4SLinus Torvalds { 3301da177e4SLinus Torvalds unsigned int dt; 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds switch(cdt) { 3331da177e4SLinus Torvalds case CDT_UNKNOWN: dt = DT_UNKNOWN; break; 3341da177e4SLinus Torvalds case CDT_FIFO: dt = DT_FIFO; break; 3351da177e4SLinus Torvalds case CDT_CHR: dt = DT_CHR; break; 3361da177e4SLinus Torvalds case CDT_DIR: dt = DT_DIR; break; 3371da177e4SLinus Torvalds case CDT_BLK: dt = DT_BLK; break; 3381da177e4SLinus Torvalds case CDT_REG: dt = DT_REG; break; 3391da177e4SLinus Torvalds case CDT_LNK: dt = DT_LNK; break; 3401da177e4SLinus Torvalds case CDT_SOCK: dt = DT_SOCK; break; 3411da177e4SLinus Torvalds case CDT_WHT: dt = DT_WHT; break; 3421da177e4SLinus Torvalds default: dt = DT_UNKNOWN; break; 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds return dt; 3451da177e4SLinus Torvalds } 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds /* support routines */ 348e924f251SAl Viro static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx) 3491da177e4SLinus Torvalds { 35097875253SJan Harkes struct coda_file_info *cfi; 35197875253SJan Harkes struct coda_inode_info *cii; 35297875253SJan Harkes struct file *host_file; 3531da177e4SLinus Torvalds struct venus_dirent *vdir; 354ee60498fSAl Viro unsigned long vdir_size = offsetof(struct venus_dirent, d_name); 3551da177e4SLinus Torvalds unsigned int type; 3561da177e4SLinus Torvalds struct qstr name; 3571da177e4SLinus Torvalds ino_t ino; 35897875253SJan Harkes int ret; 35997875253SJan Harkes 3605bb44810SFabian Frederick cfi = coda_ftoc(coda_file); 36197875253SJan Harkes host_file = cfi->cfi_container; 36297875253SJan Harkes 36393fe74b2SAl Viro cii = ITOC(file_inode(coda_file)); 3641da177e4SLinus Torvalds 365f52720caSPanagiotis Issaris vdir = kmalloc(sizeof(*vdir), GFP_KERNEL); 3661da177e4SLinus Torvalds if (!vdir) return -ENOMEM; 3671da177e4SLinus Torvalds 368e924f251SAl Viro if (!dir_emit_dots(coda_file, ctx)) 3695f47c7eaSAl Viro goto out; 370e924f251SAl Viro 3711da177e4SLinus Torvalds while (1) { 372bdd1d2d3SChristoph Hellwig loff_t pos = ctx->pos - 2; 373bdd1d2d3SChristoph Hellwig 3741da177e4SLinus Torvalds /* read entries from the directory file */ 375bdd1d2d3SChristoph Hellwig ret = kernel_read(host_file, vdir, sizeof(*vdir), &pos); 3761da177e4SLinus Torvalds if (ret < 0) { 3776d6bd94fSFabian Frederick pr_err("%s: read dir %s failed %d\n", 3786d6bd94fSFabian Frederick __func__, coda_f2s(&cii->c_fid), ret); 3791da177e4SLinus Torvalds break; 3801da177e4SLinus Torvalds } 3811da177e4SLinus Torvalds if (ret == 0) break; /* end of directory file reached */ 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds /* catch truncated reads */ 3841da177e4SLinus Torvalds if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) { 3856d6bd94fSFabian Frederick pr_err("%s: short read on %s\n", 3866d6bd94fSFabian Frederick __func__, coda_f2s(&cii->c_fid)); 3871da177e4SLinus Torvalds ret = -EBADF; 3881da177e4SLinus Torvalds break; 3891da177e4SLinus Torvalds } 3901da177e4SLinus Torvalds /* validate whether the directory file actually makes sense */ 3911da177e4SLinus Torvalds if (vdir->d_reclen < vdir_size + vdir->d_namlen) { 3926d6bd94fSFabian Frederick pr_err("%s: invalid dir %s\n", 3936d6bd94fSFabian Frederick __func__, coda_f2s(&cii->c_fid)); 3941da177e4SLinus Torvalds ret = -EBADF; 3951da177e4SLinus Torvalds break; 3961da177e4SLinus Torvalds } 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds name.len = vdir->d_namlen; 3991da177e4SLinus Torvalds name.name = vdir->d_name; 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds /* Make sure we skip '.' and '..', we already got those */ 4021da177e4SLinus Torvalds if (name.name[0] == '.' && (name.len == 1 || 403e924f251SAl Viro (name.name[1] == '.' && name.len == 2))) 4041da177e4SLinus Torvalds vdir->d_fileno = name.len = 0; 4051da177e4SLinus Torvalds 4061da177e4SLinus Torvalds /* skip null entries */ 4071da177e4SLinus Torvalds if (vdir->d_fileno && name.len) { 4086b5e1223SAl Viro ino = vdir->d_fileno; 4091da177e4SLinus Torvalds type = CDT2DT(vdir->d_type); 410e924f251SAl Viro if (!dir_emit(ctx, name.name, name.len, ino, type)) 411e924f251SAl Viro break; 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds /* we'll always have progress because d_reclen is unsigned and 4141da177e4SLinus Torvalds * we've already established it is non-zero. */ 415e924f251SAl Viro ctx->pos += vdir->d_reclen; 4161da177e4SLinus Torvalds } 4175f47c7eaSAl Viro out: 4181da177e4SLinus Torvalds kfree(vdir); 419e924f251SAl Viro return 0; 4201da177e4SLinus Torvalds } 4211da177e4SLinus Torvalds 422b625032bSFabian Frederick /* file operations for directories */ 423b625032bSFabian Frederick static int coda_readdir(struct file *coda_file, struct dir_context *ctx) 424b625032bSFabian Frederick { 425b625032bSFabian Frederick struct coda_file_info *cfi; 426b625032bSFabian Frederick struct file *host_file; 427b625032bSFabian Frederick int ret; 428b625032bSFabian Frederick 4295bb44810SFabian Frederick cfi = coda_ftoc(coda_file); 430b625032bSFabian Frederick host_file = cfi->cfi_container; 431b625032bSFabian Frederick 43261922694SAl Viro if (host_file->f_op->iterate || host_file->f_op->iterate_shared) { 433b625032bSFabian Frederick struct inode *host_inode = file_inode(host_file); 434b625032bSFabian Frederick ret = -ENOENT; 435b625032bSFabian Frederick if (!IS_DEADDIR(host_inode)) { 43661922694SAl Viro if (host_file->f_op->iterate_shared) { 43761922694SAl Viro inode_lock_shared(host_inode); 43861922694SAl Viro ret = host_file->f_op->iterate_shared(host_file, ctx); 43961922694SAl Viro file_accessed(host_file); 44061922694SAl Viro inode_unlock_shared(host_inode); 44161922694SAl Viro } else { 44261922694SAl Viro inode_lock(host_inode); 443b625032bSFabian Frederick ret = host_file->f_op->iterate(host_file, ctx); 444b625032bSFabian Frederick file_accessed(host_file); 4455955102cSAl Viro inode_unlock(host_inode); 44661922694SAl Viro } 44761922694SAl Viro } 448b625032bSFabian Frederick return ret; 449b625032bSFabian Frederick } 450b625032bSFabian Frederick /* Venus: we must read Venus dirents from a file */ 451b625032bSFabian Frederick return coda_venus_readdir(coda_file, ctx); 452b625032bSFabian Frederick } 453b625032bSFabian Frederick 4541da177e4SLinus Torvalds /* called when a cache lookup succeeds */ 4550b728e19SAl Viro static int coda_dentry_revalidate(struct dentry *de, unsigned int flags) 4561da177e4SLinus Torvalds { 45734286d66SNick Piggin struct inode *inode; 4581da177e4SLinus Torvalds struct coda_inode_info *cii; 4591da177e4SLinus Torvalds 4600b728e19SAl Viro if (flags & LOOKUP_RCU) 46134286d66SNick Piggin return -ECHILD; 46234286d66SNick Piggin 4632b0143b5SDavid Howells inode = d_inode(de); 464a7400222SAl Viro if (!inode || is_root_inode(inode)) 4651da177e4SLinus Torvalds goto out; 4661da177e4SLinus Torvalds if (is_bad_inode(inode)) 4671da177e4SLinus Torvalds goto bad; 4681da177e4SLinus Torvalds 4692b0143b5SDavid Howells cii = ITOC(d_inode(de)); 4701da177e4SLinus Torvalds if (!(cii->c_flags & (C_PURGE | C_FLUSH))) 4711da177e4SLinus Torvalds goto out; 4721da177e4SLinus Torvalds 4731da177e4SLinus Torvalds shrink_dcache_parent(de); 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds /* propagate for a flush */ 4761da177e4SLinus Torvalds if (cii->c_flags & C_FLUSH) 4771da177e4SLinus Torvalds coda_flag_inode_children(inode, C_FLUSH); 4781da177e4SLinus Torvalds 47984d08fa8SAl Viro if (d_count(de) > 1) 4801da177e4SLinus Torvalds /* pretend it's valid, but don't change the flags */ 4811da177e4SLinus Torvalds goto out; 4821da177e4SLinus Torvalds 4831da177e4SLinus Torvalds /* clear the flags. */ 484b5ce1d83SYoshihisa Abe spin_lock(&cii->c_lock); 4851da177e4SLinus Torvalds cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH); 486b5ce1d83SYoshihisa Abe spin_unlock(&cii->c_lock); 4871da177e4SLinus Torvalds bad: 4881da177e4SLinus Torvalds return 0; 4891da177e4SLinus Torvalds out: 4901da177e4SLinus Torvalds return 1; 4911da177e4SLinus Torvalds } 4921da177e4SLinus Torvalds 4931da177e4SLinus Torvalds /* 4941da177e4SLinus Torvalds * This is the callback from dput() when d_count is going to 0. 4951da177e4SLinus Torvalds * We use this to unhash dentries with bad inodes. 4961da177e4SLinus Torvalds */ 497fe15ce44SNick Piggin static int coda_dentry_delete(const struct dentry * dentry) 4981da177e4SLinus Torvalds { 49918319cb4SJan Harkes struct inode *inode; 50018319cb4SJan Harkes struct coda_inode_info *cii; 5011da177e4SLinus Torvalds 5022b0143b5SDavid Howells if (d_really_is_negative(dentry)) 5031da177e4SLinus Torvalds return 0; 5041da177e4SLinus Torvalds 50518319cb4SJan Harkes inode = d_inode(dentry); 50618319cb4SJan Harkes if (!inode || is_bad_inode(inode)) 5071da177e4SLinus Torvalds return 1; 50818319cb4SJan Harkes 50918319cb4SJan Harkes cii = ITOC(inode); 51018319cb4SJan Harkes if (cii->c_flags & C_PURGE) 51118319cb4SJan Harkes return 1; 51218319cb4SJan Harkes 5131da177e4SLinus Torvalds return 0; 5141da177e4SLinus Torvalds } 5151da177e4SLinus Torvalds 5161da177e4SLinus Torvalds 5171da177e4SLinus Torvalds 5181da177e4SLinus Torvalds /* 5191da177e4SLinus Torvalds * This is called when we want to check if the inode has 5201da177e4SLinus Torvalds * changed on the server. Coda makes this easy since the 5211da177e4SLinus Torvalds * cache manager Venus issues a downcall to the kernel when this 5221da177e4SLinus Torvalds * happens 5231da177e4SLinus Torvalds */ 52411d100d9SAl Viro int coda_revalidate_inode(struct inode *inode) 5251da177e4SLinus Torvalds { 5261da177e4SLinus Torvalds struct coda_vattr attr; 527f7cc02b8SYoshihisa Abe int error; 5281da177e4SLinus Torvalds int old_mode; 5291da177e4SLinus Torvalds ino_t old_ino; 5301da177e4SLinus Torvalds struct coda_inode_info *cii = ITOC(inode); 5311da177e4SLinus Torvalds 5321da177e4SLinus Torvalds if (!cii->c_flags) 533f7cc02b8SYoshihisa Abe return 0; 5341da177e4SLinus Torvalds 5351da177e4SLinus Torvalds if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) { 5361da177e4SLinus Torvalds error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr); 5371da177e4SLinus Torvalds if (error) 538f7cc02b8SYoshihisa Abe return -EIO; 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds /* this inode may be lost if: 5411da177e4SLinus Torvalds - it's ino changed 5421da177e4SLinus Torvalds - type changes must be permitted for repair and 5431da177e4SLinus Torvalds missing mount points. 5441da177e4SLinus Torvalds */ 5451da177e4SLinus Torvalds old_mode = inode->i_mode; 5461da177e4SLinus Torvalds old_ino = inode->i_ino; 5471da177e4SLinus Torvalds coda_vattr_to_iattr(inode, &attr); 5481da177e4SLinus Torvalds 5491da177e4SLinus Torvalds if ((old_mode & S_IFMT) != (inode->i_mode & S_IFMT)) { 550f38cfb25SFabian Frederick pr_warn("inode %ld, fid %s changed type!\n", 5511da177e4SLinus Torvalds inode->i_ino, coda_f2s(&(cii->c_fid))); 5521da177e4SLinus Torvalds } 5531da177e4SLinus Torvalds 5541da177e4SLinus Torvalds /* the following can happen when a local fid is replaced 5551da177e4SLinus Torvalds with a global one, here we lose and declare the inode bad */ 5561da177e4SLinus Torvalds if (inode->i_ino != old_ino) 557f7cc02b8SYoshihisa Abe return -EIO; 5581da177e4SLinus Torvalds 5591da177e4SLinus Torvalds coda_flag_inode_children(inode, C_FLUSH); 560b5ce1d83SYoshihisa Abe 561b5ce1d83SYoshihisa Abe spin_lock(&cii->c_lock); 5621da177e4SLinus Torvalds cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH); 563b5ce1d83SYoshihisa Abe spin_unlock(&cii->c_lock); 5641da177e4SLinus Torvalds } 5651da177e4SLinus Torvalds return 0; 5661da177e4SLinus Torvalds } 567b625032bSFabian Frederick 568b625032bSFabian Frederick const struct dentry_operations coda_dentry_operations = { 569b625032bSFabian Frederick .d_revalidate = coda_dentry_revalidate, 570b625032bSFabian Frederick .d_delete = coda_dentry_delete, 571b625032bSFabian Frederick }; 572b625032bSFabian Frederick 573b625032bSFabian Frederick const struct inode_operations coda_dir_inode_operations = { 574b625032bSFabian Frederick .create = coda_create, 575b625032bSFabian Frederick .lookup = coda_lookup, 576b625032bSFabian Frederick .link = coda_link, 577b625032bSFabian Frederick .unlink = coda_unlink, 578b625032bSFabian Frederick .symlink = coda_symlink, 579b625032bSFabian Frederick .mkdir = coda_mkdir, 580b625032bSFabian Frederick .rmdir = coda_rmdir, 581b625032bSFabian Frederick .mknod = CODA_EIO_ERROR, 582b625032bSFabian Frederick .rename = coda_rename, 583b625032bSFabian Frederick .permission = coda_permission, 584b625032bSFabian Frederick .getattr = coda_getattr, 585b625032bSFabian Frederick .setattr = coda_setattr, 586b625032bSFabian Frederick }; 587b625032bSFabian Frederick 588b625032bSFabian Frederick const struct file_operations coda_dir_operations = { 589b625032bSFabian Frederick .llseek = generic_file_llseek, 590b625032bSFabian Frederick .read = generic_read_dir, 591b625032bSFabian Frederick .iterate = coda_readdir, 592b625032bSFabian Frederick .open = coda_open, 593b625032bSFabian Frederick .release = coda_release, 594b625032bSFabian Frederick .fsync = coda_fsync, 595b625032bSFabian Frederick }; 596