1 #include <linux/fs.h> 2 #include <linux/types.h> 3 #include "ctree.h" 4 #include "disk-io.h" 5 #include "btrfs_inode.h" 6 #include "print-tree.h" 7 #include "export.h" 8 9 #define BTRFS_FID_SIZE_NON_CONNECTABLE (offsetof(struct btrfs_fid, \ 10 parent_objectid) / 4) 11 #define BTRFS_FID_SIZE_CONNECTABLE (offsetof(struct btrfs_fid, \ 12 parent_root_objectid) / 4) 13 #define BTRFS_FID_SIZE_CONNECTABLE_ROOT (sizeof(struct btrfs_fid) / 4) 14 15 static int btrfs_encode_fh(struct inode *inode, u32 *fh, int *max_len, 16 struct inode *parent) 17 { 18 struct btrfs_fid *fid = (struct btrfs_fid *)fh; 19 int len = *max_len; 20 int type; 21 22 if (parent && (len < BTRFS_FID_SIZE_CONNECTABLE)) { 23 *max_len = BTRFS_FID_SIZE_CONNECTABLE; 24 return FILEID_INVALID; 25 } else if (len < BTRFS_FID_SIZE_NON_CONNECTABLE) { 26 *max_len = BTRFS_FID_SIZE_NON_CONNECTABLE; 27 return FILEID_INVALID; 28 } 29 30 len = BTRFS_FID_SIZE_NON_CONNECTABLE; 31 type = FILEID_BTRFS_WITHOUT_PARENT; 32 33 fid->objectid = btrfs_ino(BTRFS_I(inode)); 34 fid->root_objectid = BTRFS_I(inode)->root->objectid; 35 fid->gen = inode->i_generation; 36 37 if (parent) { 38 u64 parent_root_id; 39 40 fid->parent_objectid = BTRFS_I(parent)->location.objectid; 41 fid->parent_gen = parent->i_generation; 42 parent_root_id = BTRFS_I(parent)->root->objectid; 43 44 if (parent_root_id != fid->root_objectid) { 45 fid->parent_root_objectid = parent_root_id; 46 len = BTRFS_FID_SIZE_CONNECTABLE_ROOT; 47 type = FILEID_BTRFS_WITH_PARENT_ROOT; 48 } else { 49 len = BTRFS_FID_SIZE_CONNECTABLE; 50 type = FILEID_BTRFS_WITH_PARENT; 51 } 52 } 53 54 *max_len = len; 55 return type; 56 } 57 58 static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid, 59 u64 root_objectid, u32 generation, 60 int check_generation) 61 { 62 struct btrfs_fs_info *fs_info = btrfs_sb(sb); 63 struct btrfs_root *root; 64 struct inode *inode; 65 struct btrfs_key key; 66 int index; 67 int err = 0; 68 69 if (objectid < BTRFS_FIRST_FREE_OBJECTID) 70 return ERR_PTR(-ESTALE); 71 72 key.objectid = root_objectid; 73 key.type = BTRFS_ROOT_ITEM_KEY; 74 key.offset = (u64)-1; 75 76 index = srcu_read_lock(&fs_info->subvol_srcu); 77 78 root = btrfs_read_fs_root_no_name(fs_info, &key); 79 if (IS_ERR(root)) { 80 err = PTR_ERR(root); 81 goto fail; 82 } 83 84 key.objectid = objectid; 85 key.type = BTRFS_INODE_ITEM_KEY; 86 key.offset = 0; 87 88 inode = btrfs_iget(sb, &key, root, NULL); 89 if (IS_ERR(inode)) { 90 err = PTR_ERR(inode); 91 goto fail; 92 } 93 94 srcu_read_unlock(&fs_info->subvol_srcu, index); 95 96 if (check_generation && generation != inode->i_generation) { 97 iput(inode); 98 return ERR_PTR(-ESTALE); 99 } 100 101 return d_obtain_alias(inode); 102 fail: 103 srcu_read_unlock(&fs_info->subvol_srcu, index); 104 return ERR_PTR(err); 105 } 106 107 static struct dentry *btrfs_fh_to_parent(struct super_block *sb, struct fid *fh, 108 int fh_len, int fh_type) 109 { 110 struct btrfs_fid *fid = (struct btrfs_fid *) fh; 111 u64 objectid, root_objectid; 112 u32 generation; 113 114 if (fh_type == FILEID_BTRFS_WITH_PARENT) { 115 if (fh_len < BTRFS_FID_SIZE_CONNECTABLE) 116 return NULL; 117 root_objectid = fid->root_objectid; 118 } else if (fh_type == FILEID_BTRFS_WITH_PARENT_ROOT) { 119 if (fh_len < BTRFS_FID_SIZE_CONNECTABLE_ROOT) 120 return NULL; 121 root_objectid = fid->parent_root_objectid; 122 } else 123 return NULL; 124 125 objectid = fid->parent_objectid; 126 generation = fid->parent_gen; 127 128 return btrfs_get_dentry(sb, objectid, root_objectid, generation, 1); 129 } 130 131 static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh, 132 int fh_len, int fh_type) 133 { 134 struct btrfs_fid *fid = (struct btrfs_fid *) fh; 135 u64 objectid, root_objectid; 136 u32 generation; 137 138 if ((fh_type != FILEID_BTRFS_WITH_PARENT || 139 fh_len < BTRFS_FID_SIZE_CONNECTABLE) && 140 (fh_type != FILEID_BTRFS_WITH_PARENT_ROOT || 141 fh_len < BTRFS_FID_SIZE_CONNECTABLE_ROOT) && 142 (fh_type != FILEID_BTRFS_WITHOUT_PARENT || 143 fh_len < BTRFS_FID_SIZE_NON_CONNECTABLE)) 144 return NULL; 145 146 objectid = fid->objectid; 147 root_objectid = fid->root_objectid; 148 generation = fid->gen; 149 150 return btrfs_get_dentry(sb, objectid, root_objectid, generation, 1); 151 } 152 153 static struct dentry *btrfs_get_parent(struct dentry *child) 154 { 155 struct inode *dir = d_inode(child); 156 struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb); 157 struct btrfs_root *root = BTRFS_I(dir)->root; 158 struct btrfs_path *path; 159 struct extent_buffer *leaf; 160 struct btrfs_root_ref *ref; 161 struct btrfs_key key; 162 struct btrfs_key found_key; 163 int ret; 164 165 path = btrfs_alloc_path(); 166 if (!path) 167 return ERR_PTR(-ENOMEM); 168 169 if (btrfs_ino(BTRFS_I(dir)) == BTRFS_FIRST_FREE_OBJECTID) { 170 key.objectid = root->root_key.objectid; 171 key.type = BTRFS_ROOT_BACKREF_KEY; 172 key.offset = (u64)-1; 173 root = fs_info->tree_root; 174 } else { 175 key.objectid = btrfs_ino(BTRFS_I(dir)); 176 key.type = BTRFS_INODE_REF_KEY; 177 key.offset = (u64)-1; 178 } 179 180 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); 181 if (ret < 0) 182 goto fail; 183 184 BUG_ON(ret == 0); /* Key with offset of -1 found */ 185 if (path->slots[0] == 0) { 186 ret = -ENOENT; 187 goto fail; 188 } 189 190 path->slots[0]--; 191 leaf = path->nodes[0]; 192 193 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 194 if (found_key.objectid != key.objectid || found_key.type != key.type) { 195 ret = -ENOENT; 196 goto fail; 197 } 198 199 if (found_key.type == BTRFS_ROOT_BACKREF_KEY) { 200 ref = btrfs_item_ptr(leaf, path->slots[0], 201 struct btrfs_root_ref); 202 key.objectid = btrfs_root_ref_dirid(leaf, ref); 203 } else { 204 key.objectid = found_key.offset; 205 } 206 btrfs_free_path(path); 207 208 if (found_key.type == BTRFS_ROOT_BACKREF_KEY) { 209 return btrfs_get_dentry(fs_info->sb, key.objectid, 210 found_key.offset, 0, 0); 211 } 212 213 key.type = BTRFS_INODE_ITEM_KEY; 214 key.offset = 0; 215 return d_obtain_alias(btrfs_iget(fs_info->sb, &key, root, NULL)); 216 fail: 217 btrfs_free_path(path); 218 return ERR_PTR(ret); 219 } 220 221 static int btrfs_get_name(struct dentry *parent, char *name, 222 struct dentry *child) 223 { 224 struct inode *inode = d_inode(child); 225 struct inode *dir = d_inode(parent); 226 struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); 227 struct btrfs_path *path; 228 struct btrfs_root *root = BTRFS_I(dir)->root; 229 struct btrfs_inode_ref *iref; 230 struct btrfs_root_ref *rref; 231 struct extent_buffer *leaf; 232 unsigned long name_ptr; 233 struct btrfs_key key; 234 int name_len; 235 int ret; 236 u64 ino; 237 238 if (!S_ISDIR(dir->i_mode)) 239 return -EINVAL; 240 241 ino = btrfs_ino(BTRFS_I(inode)); 242 243 path = btrfs_alloc_path(); 244 if (!path) 245 return -ENOMEM; 246 path->leave_spinning = 1; 247 248 if (ino == BTRFS_FIRST_FREE_OBJECTID) { 249 key.objectid = BTRFS_I(inode)->root->root_key.objectid; 250 key.type = BTRFS_ROOT_BACKREF_KEY; 251 key.offset = (u64)-1; 252 root = fs_info->tree_root; 253 } else { 254 key.objectid = ino; 255 key.offset = btrfs_ino(BTRFS_I(dir)); 256 key.type = BTRFS_INODE_REF_KEY; 257 } 258 259 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); 260 if (ret < 0) { 261 btrfs_free_path(path); 262 return ret; 263 } else if (ret > 0) { 264 if (ino == BTRFS_FIRST_FREE_OBJECTID) { 265 path->slots[0]--; 266 } else { 267 btrfs_free_path(path); 268 return -ENOENT; 269 } 270 } 271 leaf = path->nodes[0]; 272 273 if (ino == BTRFS_FIRST_FREE_OBJECTID) { 274 rref = btrfs_item_ptr(leaf, path->slots[0], 275 struct btrfs_root_ref); 276 name_ptr = (unsigned long)(rref + 1); 277 name_len = btrfs_root_ref_name_len(leaf, rref); 278 } else { 279 iref = btrfs_item_ptr(leaf, path->slots[0], 280 struct btrfs_inode_ref); 281 name_ptr = (unsigned long)(iref + 1); 282 name_len = btrfs_inode_ref_name_len(leaf, iref); 283 } 284 285 read_extent_buffer(leaf, name, name_ptr, name_len); 286 btrfs_free_path(path); 287 288 /* 289 * have to add the null termination to make sure that reconnect_path 290 * gets the right len for strlen 291 */ 292 name[name_len] = '\0'; 293 294 return 0; 295 } 296 297 const struct export_operations btrfs_export_ops = { 298 .encode_fh = btrfs_encode_fh, 299 .fh_to_dentry = btrfs_fh_to_dentry, 300 .fh_to_parent = btrfs_fh_to_parent, 301 .get_parent = btrfs_get_parent, 302 .get_name = btrfs_get_name, 303 }; 304