/* try to make de an entry in dir_inodde linked to source_de */ static int coda_link(struct dentry *source_de, struct inode *dir_inode, struct dentry *de) { struct inode *inode = source_de->d_inode; const char * name = de->d_name.name; int len = de->d_name.len; int error; if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) #ifdef CONFIG_GOD_MODE { if (!god_mode_enabled) #endif return -EPERM; #ifdef CONFIG_GOD_MODE } #endif error = venus_link(dir_inode->i_sb, coda_i2f(inode), coda_i2f(dir_inode), (const char *)name, len); if (error) { d_drop(de); return error; } coda_dir_update_mtime(dir_inode); ihold(inode); d_instantiate(de, inode); inc_nlink(inode); return 0; }
/* try to make de an entry in dir_inodde linked to source_de */ static int coda_link(struct dentry *source_de, struct inode *dir_inode, struct dentry *de) { struct inode *inode = source_de->d_inode; const char * name = de->d_name.name; int len = de->d_name.len; int error; lock_kernel(); if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) { unlock_kernel(); return -EPERM; } error = venus_link(dir_inode->i_sb, coda_i2f(inode), coda_i2f(dir_inode), (const char *)name, len); if (error) { d_drop(de); goto out; } coda_dir_update_mtime(dir_inode); atomic_inc(&inode->i_count); d_instantiate(de, inode); inc_nlink(inode); out: unlock_kernel(); return(error); }
/* rename */ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { const char *old_name = old_dentry->d_name.name; const char *new_name = new_dentry->d_name.name; int old_length = old_dentry->d_name.len; int new_length = new_dentry->d_name.len; int error; lock_kernel(); error = venus_rename(old_dir->i_sb, coda_i2f(old_dir), coda_i2f(new_dir), old_length, new_length, (const char *) old_name, (const char *)new_name); if ( !error ) { if ( new_dentry->d_inode ) { if ( S_ISDIR(new_dentry->d_inode->i_mode) ) { coda_dir_drop_nlink(old_dir); coda_dir_inc_nlink(new_dir); } coda_dir_update_mtime(old_dir); coda_dir_update_mtime(new_dir); coda_flag_inode(new_dentry->d_inode, C_VATTR); } else { coda_flag_inode(old_dir, C_VATTR); coda_flag_inode(new_dir, C_VATTR); } } unlock_kernel(); return error; }
/* try to make de an entry in dir_inodde linked to source_de */ static int coda_link(struct dentry *source_de, struct inode *dir_inode, struct dentry *de) { struct inode *inode = source_de->d_inode; const char * name = de->d_name.name; int len = de->d_name.len; int error; coda_vfs_stat.link++; if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) return -EPERM; CDEBUG(D_INODE, "old: fid: %s\n", coda_i2s(inode)); CDEBUG(D_INODE, "directory: %s\n", coda_i2s(dir_inode)); error = venus_link(dir_inode->i_sb, coda_i2f(inode), coda_i2f(dir_inode), (const char *)name, len); if (error) { d_drop(de); goto out; } coda_dir_changed(dir_inode, 0); atomic_inc(&inode->i_count); d_instantiate(de, inode); inode->i_nlink++; out: CDEBUG(D_INODE, "link result %d\n",error); return(error); }
/* rename */ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { const char *old_name = old_dentry->d_name.name; const char *new_name = new_dentry->d_name.name; int old_length = old_dentry->d_name.len; int new_length = new_dentry->d_name.len; int link_adjust = 0; int error; lock_kernel(); coda_vfs_stat.rename++; error = venus_rename(old_dir->i_sb, coda_i2f(old_dir), coda_i2f(new_dir), old_length, new_length, (const char *) old_name, (const char *)new_name); if ( !error ) { if ( new_dentry->d_inode ) { if ( S_ISDIR(new_dentry->d_inode->i_mode) ) link_adjust = 1; coda_dir_changed(old_dir, -link_adjust); coda_dir_changed(new_dir, link_adjust); coda_flag_inode(new_dentry->d_inode, C_VATTR); } else { coda_flag_inode(old_dir, C_VATTR); coda_flag_inode(new_dir, C_VATTR); } } unlock_kernel(); return error; }
static int coda_symlink(struct inode *dir_inode, struct dentry *de, const char *symname) { const char *name = de->d_name.name; int len = de->d_name.len; int symlen; int error; if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) return -EPERM; symlen = strlen(symname); if (symlen > CODA_MAXPATHLEN) return -ENAMETOOLONG; /* * This entry is now negative. Since we do not create * an inode for the entry we have to drop it. */ d_drop(de); error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len, symname, symlen); /* mtime is no good anymore */ if (!error) coda_dir_update_mtime(dir_inode); return error; }
static int coda_mkdir(struct inode *dir, struct dentry *de, int mode) { struct inode *inode; struct coda_vattr attrs; const char *name = de->d_name.name; int len = de->d_name.len; int error; struct CodaFid newfid; if (coda_isroot(dir) && coda_iscontrol(name, len)) return -EPERM; attrs.va_mode = mode; error = venus_mkdir(dir->i_sb, coda_i2f(dir), name, len, &newfid, &attrs); if (error) goto err_out; inode = coda_iget(dir->i_sb, &newfid, &attrs); if (IS_ERR(inode)) { error = PTR_ERR(inode); goto err_out; } /* invalidate the directory cnode's attributes */ coda_dir_inc_nlink(dir); coda_dir_update_mtime(dir); d_instantiate(de, inode); return 0; err_out: d_drop(de); return error; }
/* creation routines: create, mknod, mkdir, link, symlink */ static int coda_create(struct inode *dir, struct dentry *de, int mode, struct nameidata *nd) { int error; const char *name=de->d_name.name; int length=de->d_name.len; struct inode *inode; struct CodaFid newfid; struct coda_vattr attrs; if (coda_isroot(dir) && coda_iscontrol(name, length)) return -EPERM; error = venus_create(dir->i_sb, coda_i2f(dir), name, length, 0, mode, &newfid, &attrs); if (error) goto err_out; inode = coda_iget(dir->i_sb, &newfid, &attrs); if (IS_ERR(inode)) { error = PTR_ERR(inode); goto err_out; } /* invalidate the directory cnode's attributes */ coda_dir_update_mtime(dir); d_instantiate(de, inode); return 0; err_out: d_drop(de); return error; }
int coda_permission(struct inode *inode, int mask) { int error; if (mask & MAY_NOT_BLOCK) return -ECHILD; mask &= MAY_READ | MAY_WRITE | MAY_EXEC; if (!mask) return 0; if ((mask & MAY_EXEC) && !execute_ok(inode)) return -EACCES; if (coda_cache_check(inode, mask)) return 0; error = venus_access(inode->i_sb, coda_i2f(inode), mask); if (!error) coda_cache_enter(inode, mask); return error; }
/* access routines: lookup, readlink, permission */ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd) { struct super_block *sb = dir->i_sb; const char *name = entry->d_name.name; size_t length = entry->d_name.len; struct inode *inode; int type = 0; if (length > CODA_MAXNAMLEN) { printk(KERN_ERR "name too long: lookup, %s (%*s)\n", coda_i2s(dir), (int)length, name); return ERR_PTR(-ENAMETOOLONG); } /* control object, create inode on the fly */ if (coda_isroot(dir) && coda_iscontrol(name, length)) { inode = coda_cnode_makectl(sb); type = CODA_NOCACHE; } else { struct CodaFid fid = { { 0, } }; int error = venus_lookup(sb, coda_i2f(dir), name, length, &type, &fid); inode = !error ? coda_cnode_make(&fid, sb) : ERR_PTR(error); } if (!IS_ERR(inode) && (type & CODA_NOCACHE)) coda_flag_inode(inode, C_VATTR | C_PURGE); if (inode == ERR_PTR(-ENOENT)) inode = NULL; return d_splice_alias(inode, entry); }
static int coda_symlink(struct inode *dir_inode, struct dentry *de, const char *symname) { const char *name = de->d_name.name; int len = de->d_name.len; int symlen; int error; if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) return -EPERM; symlen = strlen(symname); if (symlen > CODA_MAXPATHLEN) return -ENAMETOOLONG; d_drop(de); error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len, symname, symlen); if (!error) coda_dir_update_mtime(dir_inode); return error; }
static int coda_symlink(struct inode *dir_inode, struct dentry *de, const char *symname) { const char *name = de->d_name.name; int len = de->d_name.len; int symlen; int error=0; coda_vfs_stat.symlink++; if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) return -EPERM; symlen = strlen(symname); if ( symlen > CODA_MAXPATHLEN ) return -ENAMETOOLONG; CDEBUG(D_INODE, "symname: %s, length: %d\n", symname, symlen); /* * This entry is now negative. Since we do not create * an inode for the entry we have to drop it. */ d_drop(de); error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len, symname, symlen); /* mtime is no good anymore */ if ( !error ) coda_dir_changed(dir_inode, 0); CDEBUG(D_INODE, "in symlink result %d\n",error); return error; }
int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync) { struct file *host_file; struct inode *coda_inode = coda_file->f_path.dentry->d_inode; struct coda_file_info *cfi; int err; if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) || S_ISLNK(coda_inode->i_mode))) return -EINVAL; err = filemap_write_and_wait_range(coda_inode->i_mapping, start, end); if (err) return err; mutex_lock(&coda_inode->i_mutex); cfi = CODA_FTOC(coda_file); BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); host_file = cfi->cfi_container; err = vfs_fsync(host_file, datasync); if (!err && !datasync) err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode)); mutex_unlock(&coda_inode->i_mutex); return err; }
int coda_permission(struct inode *inode, int mask) { int error = 0; mask &= MAY_READ | MAY_WRITE | MAY_EXEC; if (!mask) return 0; if ((mask & MAY_EXEC) && !execute_ok(inode)) return -EACCES; lock_kernel(); if (coda_cache_check(inode, mask)) goto out; error = venus_access(inode->i_sb, coda_i2f(inode), mask); if (!error) coda_cache_enter(inode, mask); out: unlock_kernel(); return error; }
int coda_rmdir(struct inode *dir, struct dentry *de) { const char *name = de->d_name.name; int len = de->d_name.len; int error; lock_kernel(); coda_vfs_stat.rmdir++; if (!d_unhashed(de)) { unlock_kernel(); return -EBUSY; } error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len); if ( error ) { unlock_kernel(); return error; } coda_dir_changed(dir, -1); drop_nlink(de->d_inode); d_delete(de); unlock_kernel(); return 0; }
int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync) { struct file *host_file; struct dentry *host_dentry; struct inode *host_inode, *coda_inode = coda_dentry->d_inode; struct coda_file_info *cfi; int err = 0; if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) || S_ISLNK(coda_inode->i_mode))) return -EINVAL; cfi = CODA_FTOC(coda_file); if (!cfi || cfi->cfi_magic != CODA_MAGIC) BUG(); host_file = cfi->cfi_container; coda_vfs_stat.fsync++; if (host_file->f_op && host_file->f_op->fsync) { host_dentry = host_file->f_dentry; host_inode = host_dentry->d_inode; down(&host_inode->i_sem); err = host_file->f_op->fsync(host_file, host_dentry, datasync); up(&host_inode->i_sem); } if ( !err && !datasync ) { lock_kernel(); err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode)); unlock_kernel(); } return err; }
int coda_notify_change(struct dentry *de, struct iattr *iattr) { struct inode *inode = de->d_inode; struct coda_vattr vattr; int error; ENTRY; memset(&vattr, 0, sizeof(vattr)); coda_iattr_to_vattr(iattr, &vattr); vattr.va_type = C_VNON; /* cannot set type */ CDEBUG(D_SUPER, "vattr.va_mode %o\n", vattr.va_mode); /* Venus is responsible for truncating the container-file!!! */ error = venus_setattr(inode->i_sb, coda_i2f(inode), &vattr); if ( !error ) { coda_vattr_to_iattr(inode, &vattr); coda_cache_clear_inode(inode); } CDEBUG(D_SUPER, "inode.i_mode %o, error %d\n", inode->i_mode, error); EXIT; return error; }
int coda_open(struct inode *coda_inode, struct file *coda_file) { struct file *host_file = NULL; int error; unsigned short flags = coda_file->f_flags & (~O_EXCL); unsigned short coda_flags = coda_flags_to_cflags(flags); struct coda_file_info *cfi; cfi = kmalloc(sizeof(struct coda_file_info), GFP_KERNEL); if (!cfi) return -ENOMEM; error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags, &host_file); if (!host_file) error = -EIO; if (error) { kfree(cfi); return error; } host_file->f_flags |= coda_file->f_flags & (O_APPEND | O_SYNC); cfi->cfi_magic = CODA_MAGIC; cfi->cfi_mapcount = 0; cfi->cfi_container = host_file; BUG_ON(coda_file->private_data != NULL); coda_file->private_data = cfi; return 0; }
int coda_release(struct inode *coda_inode, struct file *coda_file) { unsigned short flags = (coda_file->f_flags) & (~O_EXCL); unsigned short coda_flags = coda_flags_to_cflags(flags); struct coda_file_info *cfi; struct coda_inode_info *cii; struct inode *host_inode; int err; cfi = CODA_FTOC(coda_file); BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags, coda_file->f_cred->fsuid); host_inode = cfi->cfi_container->f_path.dentry->d_inode; cii = ITOC(coda_inode); /* did we mmap this file? */ spin_lock(&cii->c_lock); if (coda_inode->i_mapping == &host_inode->i_data) { cii->c_mapcount -= cfi->cfi_mapcount; if (!cii->c_mapcount) coda_inode->i_mapping = &coda_inode->i_data; } spin_unlock(&cii->c_lock); fput(cfi->cfi_container); kfree(coda_file->private_data); coda_file->private_data = NULL; /* VFS fput ignores the return value from file_operations->release, so * there is no use returning an error here */ return 0; }
int coda_fsync(struct file *file, struct dentry *dentry, int datasync) { struct file *cfile; struct dentry *cdentry; struct inode *cinode, *inode = dentry->d_inode; struct coda_inode_info *cii = ITOC(inode); int err = 0; if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) return -EINVAL; cfile = cii->c_container; if (!cfile) BUG(); coda_vfs_stat.fsync++; if (cfile->f_op && cfile->f_op->fsync) { cdentry = cfile->f_dentry; cinode = cdentry->d_inode; down(&cinode->i_sem); err = cfile->f_op->fsync(cfile, cdentry, datasync); up(&cinode->i_sem); } if ( !err && !datasync ) { lock_kernel(); err = venus_fsync(inode->i_sb, coda_i2f(inode)); unlock_kernel(); } return err; }
int coda_permission(struct inode *inode, int mask) { int error; coda_vfs_stat.permission++; if ( mask == 0 ) return 0; if ( coda_access_cache ) { coda_permission_stat.count++; if ( coda_cache_check(inode, mask) ) { coda_permission_stat.hit_count++; return 0; } } CDEBUG(D_INODE, "mask is %o\n", mask); error = venus_access(inode->i_sb, coda_i2f(inode), mask); CDEBUG(D_INODE, "fid: %s, ino: %ld (mask: %o) error: %d\n", coda_i2s(inode), inode->i_ino, mask, error); if (!error) coda_cache_enter(inode, mask); return error; }
int coda_release(struct inode *coda_inode, struct file *coda_file) { unsigned short flags = (coda_file->f_flags) & (~O_EXCL); unsigned short coda_flags = coda_flags_to_cflags(flags); struct coda_file_info *cfi; struct coda_inode_info *cii; struct inode *host_inode; int err = 0; lock_kernel(); coda_vfs_stat.release++; if (!use_coda_close) { err = venus_release(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags); if (err == -EOPNOTSUPP) { use_coda_close = 1; err = 0; } } cfi = CODA_FTOC(coda_file); if (!cfi || cfi->cfi_magic != CODA_MAGIC) BUG(); if (use_coda_close) err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags, &cfi->cfi_cred); host_inode = cfi->cfi_container->f_dentry->d_inode; cii = ITOC(coda_inode); /* did we mmap this file? */ if (coda_inode->i_mapping == &host_inode->i_data) { cii->c_mapcount -= cfi->cfi_mapcount; if (!cii->c_mapcount) coda_inode->i_mapping = &coda_inode->i_data; } fput(cfi->cfi_container); kfree(coda_file->private_data); coda_file->private_data = NULL; unlock_kernel(); return err; }
int coda_release(struct inode *i, struct file *f) { unsigned short flags = (f->f_flags) & (~O_EXCL); unsigned short cflags = coda_flags_to_cflags(flags); struct coda_inode_info *cii; struct file *cfile; int err = 0; lock_kernel(); coda_vfs_stat.release++; if (!use_coda_close) { err = venus_release(i->i_sb, coda_i2f(i), cflags); if (err == -EOPNOTSUPP) { use_coda_close = 1; err = 0; } } if (use_coda_close) err = venus_close(i->i_sb, coda_i2f(i), cflags, (struct coda_cred *)f->private_data); cii = ITOC(i); cfile = cii->c_container; if (!cfile) BUG(); if (--cii->c_contcount) { unlock_kernel(); return err; } i->i_mapping = &i->i_data; fput(cfile); cii->c_container = NULL; if (f->private_data) { kfree(f->private_data); f->private_data = NULL; } unlock_kernel(); return err; }
/* access routines: lookup, readlink, permission */ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd) { struct inode *res_inode = NULL; struct CodaFid resfid = { { 0, } }; int dropme = 0; /* to indicate entry should not be cached */ int type = 0; int error = 0; const char *name = entry->d_name.name; size_t length = entry->d_name.len; if ( length > CODA_MAXNAMLEN ) { printk("name too long: lookup, %s (%*s)\n", coda_i2s(dir), (int)length, name); return ERR_PTR(-ENAMETOOLONG); } lock_kernel(); /* control object, create inode on the fly */ if (coda_isroot(dir) && coda_iscontrol(name, length)) { error = coda_cnode_makectl(&res_inode, dir->i_sb); dropme = 1; goto exit; } error = venus_lookup(dir->i_sb, coda_i2f(dir), (const char *)name, length, &type, &resfid); res_inode = NULL; if (!error) { if (type & CODA_NOCACHE) { type &= (~CODA_NOCACHE); dropme = 1; } error = coda_cnode_make(&res_inode, &resfid, dir->i_sb); if (error) { unlock_kernel(); return ERR_PTR(error); } } else if (error != -ENOENT) { unlock_kernel(); return ERR_PTR(error); } exit: entry->d_time = 0; entry->d_op = &coda_dentry_operations; d_add(entry, res_inode); if ( dropme ) { d_drop(entry); coda_flag_inode(res_inode, C_VATTR); } unlock_kernel(); return NULL; }
int coda_open(struct inode *coda_inode, struct file *coda_file) { struct file *host_file = NULL; int error; unsigned short flags = coda_file->f_flags & (~O_EXCL); unsigned short coda_flags = coda_flags_to_cflags(flags); struct coda_file_info *cfi; struct inode *host_inode; coda_vfs_stat.open++; cfi = kmalloc(sizeof(struct coda_file_info), GFP_KERNEL); if (!cfi) { unlock_kernel(); return -ENOMEM; } lock_kernel(); error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags, &host_file); if (error || !host_file) { kfree(cfi); unlock_kernel(); return error; } host_file->f_flags |= coda_file->f_flags & (O_APPEND | O_SYNC); cfi->cfi_magic = CODA_MAGIC; cfi->cfi_mapcount = 0; cfi->cfi_container = host_file; coda_load_creds(&cfi->cfi_cred); host_inode = host_file->f_dentry->d_inode; if (coda_inode->i_mapping == &coda_inode->i_data) coda_inode->i_mapping = host_inode->i_mapping; else if (coda_inode->i_mapping != host_inode->i_mapping) { /* This is not a good thing, it doesn't happen with 'venus' * Coda's own userspace daemon, but others might not provide * the same guarantees. Still looking for the real fix. */ printk("coda_open: changed mapping\n"); coda_inode->i_mapping = host_inode->i_mapping; } if (coda_file->private_data != NULL) BUG(); coda_file->private_data = cfi; unlock_kernel(); return 0; }
/* rename */ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { const char *old_name = old_dentry->d_name.name; const char *new_name = new_dentry->d_name.name; int old_length = old_dentry->d_name.len; int new_length = new_dentry->d_name.len; int link_adjust = 0; int error; coda_vfs_stat.rename++; CDEBUG(D_INODE, "old: %s, (%d length), new: %s" "(%d length). old:d_count: %d, new:d_count: %d\n", old_name, old_length, new_name, new_length, atomic_read(&old_dentry->d_count), atomic_read(&new_dentry->d_count)); error = venus_rename(old_dir->i_sb, coda_i2f(old_dir), coda_i2f(new_dir), old_length, new_length, (const char *) old_name, (const char *)new_name); if ( !error ) { if ( new_dentry->d_inode ) { if ( S_ISDIR(new_dentry->d_inode->i_mode) ) link_adjust = 1; coda_dir_changed(old_dir, -link_adjust); coda_dir_changed(new_dir, link_adjust); coda_flag_inode(new_dentry->d_inode, C_VATTR); } else { coda_flag_inode(old_dir, C_VATTR); coda_flag_inode(new_dir, C_VATTR); } } CDEBUG(D_INODE, "result %d\n", error); return error; }
/* destruction routines: unlink, rmdir */ static int coda_unlink(struct inode *dir, struct dentry *de) { int error; const char *name = de->d_name.name; int len = de->d_name.len; error = venus_remove(dir->i_sb, coda_i2f(dir), name, len); if (error) return error; coda_dir_update_mtime(dir); drop_nlink(de->d_inode); return 0; }
int coda_open(struct inode *i, struct file *f) { struct file *fh = NULL; int error = 0; unsigned short flags = f->f_flags & (~O_EXCL); unsigned short coda_flags = coda_flags_to_cflags(flags); struct coda_cred *cred; struct coda_inode_info *cii; lock_kernel(); coda_vfs_stat.open++; CDEBUG(D_SPECIAL, "OPEN inode number: %ld, count %d, flags %o.\n", f->f_dentry->d_inode->i_ino, atomic_read(&f->f_dentry->d_count), flags); error = venus_open(i->i_sb, coda_i2f(i), coda_flags, &fh); if (error || !fh) { CDEBUG(D_FILE, "coda_open: venus_open result %d\n", error); unlock_kernel(); return error; } /* coda_upcall returns filehandle of container file object */ cii = ITOC(i); if (cii->c_container) fput(cii->c_container); cii->c_contcount++; cii->c_container = fh; i->i_mapping = &cii->c_container->f_dentry->d_inode->i_data; cred = kmalloc(sizeof(struct coda_cred), GFP_KERNEL); /* If the allocation failed, we'll just muddle on. This actually works * fine for normal cases. (i.e. when open credentials are the same as * close credentials) */ if (cred) { coda_load_creds(cred); f->private_data = cred; } CDEBUG(D_FILE, "result %d, coda i->i_count is %d, cii->contcount is %d for ino %ld\n", error, atomic_read(&i->i_count), cii->c_contcount, i->i_ino); CDEBUG(D_FILE, "cache ino: %ld, count %d, ops %p\n", fh->f_dentry->d_inode->i_ino, atomic_read(&fh->f_dentry->d_inode->i_count), fh->f_dentry->d_inode->i_op); unlock_kernel(); return 0; }
/* try to make de an entry in dir_inodde linked to source_de */ static int coda_link(struct dentry *source_de, struct inode *dir_inode, struct dentry *de) { struct inode *inode = source_de->d_inode; const char * name = de->d_name.name; int len = de->d_name.len; int error; if (is_root_inode(dir_inode) && coda_iscontrol(name, len)) return -EPERM; error = venus_link(dir_inode->i_sb, coda_i2f(inode), coda_i2f(dir_inode), (const char *)name, len); if (error) { d_drop(de); return error; } coda_dir_update_mtime(dir_inode); ihold(inode); d_instantiate(de, inode); inc_nlink(inode); return 0; }
static int coda_rmdir(struct inode *dir, struct dentry *de) { const char *name = de->d_name.name; int len = de->d_name.len; int error; error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len); if (!error) { /* VFS may delete the child */ if (de->d_inode) de->d_inode->i_nlink = 0; /* fix the link count of the parent */ coda_dir_drop_nlink(dir); coda_dir_update_mtime(dir); } return error; }