| 1 | |
| 2 | |
| 3 | (C) 1996 Peter Braam
|
| 4 |
|
| 5 |
|
| 6 | #include <linux/types.h>
|
| 7 | #include <linux/string.h>
|
| 8 | #include <linux/time.h>
|
| 9 |
|
| 10 | #include <linux/coda.h>
|
| 11 | #include <linux/pagemap.h>
|
| 12 | #include "coda_psdev.h"
|
| 13 | #include "coda_linux.h"
|
| 14 |
|
| 15 | static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2)
|
| 16 | {
|
| 17 | return memcmp(fid1, fid2, sizeof(*fid1)) == 0;
|
| 18 | }
|
| 19 |
|
| 20 | static const struct inode_operations coda_symlink_inode_operations = {
|
| 21 | .get_link = page_get_link,
|
| 22 | .setattr = coda_setattr,
|
| 23 | };
|
| 24 |
|
| 25 |
|
| 26 | static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
|
| 27 | {
|
| 28 | coda_vattr_to_iattr(inode, attr);
|
| 29 |
|
| 30 | if (S_ISREG(inode->i_mode)) {
|
| 31 | inode->i_op = &coda_file_inode_operations;
|
| 32 | inode->i_fop = &coda_file_operations;
|
| 33 | } else if (S_ISDIR(inode->i_mode)) {
|
| 34 | inode->i_op = &coda_dir_inode_operations;
|
| 35 | inode->i_fop = &coda_dir_operations;
|
| 36 | } else if (S_ISLNK(inode->i_mode)) {
|
| 37 | inode->i_op = &coda_symlink_inode_operations;
|
| 38 | inode_nohighmem(inode);
|
| 39 | inode->i_data.a_ops = &coda_symlink_aops;
|
| 40 | inode->i_mapping = &inode->i_data;
|
| 41 | } else
|
| 42 | init_special_inode(inode, inode->i_mode, huge_decode_dev(attr->va_rdev));
|
| 43 | }
|
| 44 |
|
| 45 | static int coda_test_inode(struct inode *inode, void *data)
|
| 46 | {
|
| 47 | struct CodaFid *fid = (struct CodaFid *)data;
|
| 48 | struct coda_inode_info *cii = ITOC(inode);
|
| 49 | return coda_fideq(&cii->c_fid, fid);
|
| 50 | }
|
| 51 |
|
| 52 | static int coda_set_inode(struct inode *inode, void *data)
|
| 53 | {
|
| 54 | struct CodaFid *fid = (struct CodaFid *)data;
|
| 55 | struct coda_inode_info *cii = ITOC(inode);
|
| 56 | cii->c_fid = *fid;
|
| 57 | return 0;
|
| 58 | }
|
| 59 |
|
| 60 | struct inode * coda_iget(struct super_block * sb, struct CodaFid * fid,
|
| 61 | struct coda_vattr * attr)
|
| 62 | {
|
| 63 | struct inode *inode;
|
| 64 | struct coda_inode_info *cii;
|
| 65 | unsigned long hash = coda_f2i(fid);
|
| 66 | umode_t inode_type = coda_inode_type(attr);
|
| 67 |
|
| 68 | retry:
|
| 69 | inode = iget5_locked(sb, hash, coda_test_inode, coda_set_inode, fid);
|
| 70 | if (!inode)
|
| 71 | return ERR_PTR(-ENOMEM);
|
| 72 |
|
| 73 | if (inode_state_read_once(inode) & I_NEW) {
|
| 74 | cii = ITOC(inode);
|
| 75 |
|
| 76 | inode->i_ino = hash;
|
| 77 |
|
| 78 | cii->c_mapcount = 0;
|
| 79 | coda_fill_inode(inode, attr);
|
| 80 | unlock_new_inode(inode);
|
| 81 | } else if ((inode->i_mode & S_IFMT) != inode_type) {
|
| 82 |
|
| 83 | remove_inode_hash(inode);
|
| 84 | coda_flag_inode(inode, C_PURGE);
|
| 85 | iput(inode);
|
| 86 | goto retry;
|
| 87 | }
|
| 88 | return inode;
|
| 89 | }
|
| 90 |
|
| 91 | |
| 92 | - get attributes (might be cached)
|
| 93 | - get the inode for the fid using vfs iget
|
| 94 | - link the two up if this is needed
|
| 95 | - fill in the attributes
|
| 96 |
|
| 97 | struct inode *coda_cnode_make(struct CodaFid *fid, struct super_block *sb)
|
| 98 | {
|
| 99 | struct coda_vattr attr;
|
| 100 | struct inode *inode;
|
| 101 | int error;
|
| 102 |
|
| 103 |
|
| 104 | error = venus_getattr(sb, fid, &attr);
|
| 105 | if (error)
|
| 106 | return ERR_PTR(error);
|
| 107 |
|
| 108 | inode = coda_iget(sb, fid, &attr);
|
| 109 | if (IS_ERR(inode))
|
| 110 | pr_warn("%s: coda_iget failed\n", __func__);
|
| 111 | return inode;
|
| 112 | }
|
| 113 |
|
| 114 |
|
| 115 | |
| 116 | * special case for files created during a disconnection where they may
|
| 117 | * not be globally unique. When an identifier collision is detected we
|
| 118 | * first try to flush the cached inode from the kernel and finally
|
| 119 | * resort to renaming/rehashing in-place. Userspace remembers both old
|
| 120 | * and new values of the identifier to handle any in-flight upcalls.
|
| 121 | * The real solution is to use globally unique UUIDs as identifiers, but
|
| 122 | * retrofitting the existing userspace code for this is non-trivial.
|
| 123 | void coda_replace_fid(struct inode *inode, struct CodaFid *oldfid,
|
| 124 | struct CodaFid *newfid)
|
| 125 | {
|
| 126 | struct coda_inode_info *cii = ITOC(inode);
|
| 127 | unsigned long hash = coda_f2i(newfid);
|
| 128 |
|
| 129 | BUG_ON(!coda_fideq(&cii->c_fid, oldfid));
|
| 130 |
|
| 131 |
|
| 132 |
|
| 133 | remove_inode_hash(inode);
|
| 134 | cii->c_fid = *newfid;
|
| 135 | inode->i_ino = hash;
|
| 136 | __insert_inode_hash(inode, hash);
|
| 137 | }
|
| 138 |
|
| 139 |
|
| 140 | struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb)
|
| 141 | {
|
| 142 | struct inode *inode;
|
| 143 | unsigned long hash = coda_f2i(fid);
|
| 144 |
|
| 145 | inode = ilookup5(sb, hash, coda_test_inode, fid);
|
| 146 | if ( !inode )
|
| 147 | return NULL;
|
| 148 |
|
| 149 | |
| 150 | * fail in the initialization callback
|
| 151 | BUG_ON(inode_state_read_once(inode) & I_NEW);
|
| 152 |
|
| 153 | return inode;
|
| 154 | }
|
| 155 |
|
| 156 | struct coda_file_info *coda_ftoc(struct file *file)
|
| 157 | {
|
| 158 | struct coda_file_info *cfi = file->private_data;
|
| 159 |
|
| 160 | BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
|
| 161 |
|
| 162 | return cfi;
|
| 163 |
|
| 164 | }
|
| 165 |
|
| 166 |
|
| 167 | struct inode *coda_cnode_makectl(struct super_block *sb)
|
| 168 | {
|
| 169 | struct inode *inode = new_inode(sb);
|
| 170 | if (inode) {
|
| 171 | inode->i_ino = CTL_INO;
|
| 172 | inode->i_op = &coda_ioctl_inode_operations;
|
| 173 | inode->i_fop = &coda_ioctl_operations;
|
| 174 | inode->i_mode = 0444;
|
| 175 | return inode;
|
| 176 | }
|
| 177 | return ERR_PTR(-ENOMEM);
|
| 178 | }
|
| 179 |
|