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