Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'vfs-6.13.exportfs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull vfs exportfs updates from Christian Brauner:
"This contains work to bring NFS connectable file handles to userspace
servers.

The name_to_handle_at() system call is extended to encode connectable
file handles. Such file handles can be resolved to an open file with a
connected path. So far userspace NFS servers couldn't make use of this
functionality even though the kernel does already support it. This is
achieved by introducing a new flag for name_to_handle_at().

Similarly, the open_by_handle_at() system call is tought to understand
connectable file handles explicitly created via name_to_handle_at()"

* tag 'vfs-6.13.exportfs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
fs: open_by_handle_at() support for decoding "explicit connectable" file handles
fs: name_to_handle_at() support for "explicit connectable" file handles
fs: prepare for "explicit connectable" file handles

+98 -8
+15 -2
fs/exportfs/expfs.c
··· 382 382 int *max_len, struct inode *parent, int flags) 383 383 { 384 384 const struct export_operations *nop = inode->i_sb->s_export_op; 385 + enum fid_type type; 385 386 386 387 if (!exportfs_can_encode_fh(nop, flags)) 387 388 return -EOPNOTSUPP; 388 389 389 390 if (!nop && (flags & EXPORT_FH_FID)) 390 - return exportfs_encode_ino64_fid(inode, fid, max_len); 391 + type = exportfs_encode_ino64_fid(inode, fid, max_len); 392 + else 393 + type = nop->encode_fh(inode, fid->raw, max_len, parent); 391 394 392 - return nop->encode_fh(inode, fid->raw, max_len, parent); 395 + if (type > 0 && FILEID_USER_FLAGS(type)) { 396 + pr_warn_once("%s: unexpected fh type value 0x%x from fstype %s.\n", 397 + __func__, type, inode->i_sb->s_type->name); 398 + return -EINVAL; 399 + } 400 + 401 + return type; 402 + 393 403 } 394 404 EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh); 395 405 ··· 445 435 struct dentry *result, *alias; 446 436 char nbuf[NAME_MAX+1]; 447 437 int err; 438 + 439 + if (fileid_type < 0 || FILEID_USER_FLAGS(fileid_type)) 440 + return ERR_PTR(-EINVAL); 448 441 449 442 /* 450 443 * Try to get any dentry for the given file handle from the filesystem.
+69 -6
fs/fhandle.c
··· 31 31 if (!exportfs_can_encode_fh(path->dentry->d_sb->s_export_op, fh_flags)) 32 32 return -EOPNOTSUPP; 33 33 34 + /* 35 + * A request to encode a connectable handle for a disconnected dentry 36 + * is unexpected since AT_EMPTY_PATH is not allowed. 37 + */ 38 + if (fh_flags & EXPORT_FH_CONNECTABLE && 39 + WARN_ON(path->dentry->d_flags & DCACHE_DISCONNECTED)) 40 + return -EINVAL; 41 + 34 42 if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle))) 35 43 return -EFAULT; 36 44 ··· 53 45 /* convert handle size to multiple of sizeof(u32) */ 54 46 handle_dwords = f_handle.handle_bytes >> 2; 55 47 56 - /* we ask for a non connectable maybe decodeable file handle */ 48 + /* Encode a possibly decodeable/connectable file handle */ 57 49 retval = exportfs_encode_fh(path->dentry, 58 50 (struct fid *)handle->f_handle, 59 51 &handle_dwords, fh_flags); ··· 75 67 * non variable part of the file_handle 76 68 */ 77 69 handle_bytes = 0; 78 - } else 70 + } else { 71 + /* 72 + * When asked to encode a connectable file handle, encode this 73 + * property in the file handle itself, so that we later know 74 + * how to decode it. 75 + * For sanity, also encode in the file handle if the encoded 76 + * object is a directory and verify this during decode, because 77 + * decoding directory file handles is quite different than 78 + * decoding connectable non-directory file handles. 79 + */ 80 + if (fh_flags & EXPORT_FH_CONNECTABLE) { 81 + handle->handle_type |= FILEID_IS_CONNECTABLE; 82 + if (d_is_dir(path->dentry)) 83 + fh_flags |= FILEID_IS_DIR; 84 + } 79 85 retval = 0; 86 + } 80 87 /* copy the mount id */ 81 88 if (unique_mntid) { 82 89 if (put_user(real_mount(path->mnt)->mnt_id_unique, ··· 132 109 { 133 110 struct path path; 134 111 int lookup_flags; 135 - int fh_flags; 112 + int fh_flags = 0; 136 113 int err; 137 114 138 115 if (flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH | AT_HANDLE_FID | 139 - AT_HANDLE_MNT_ID_UNIQUE)) 116 + AT_HANDLE_MNT_ID_UNIQUE | AT_HANDLE_CONNECTABLE)) 140 117 return -EINVAL; 141 118 119 + /* 120 + * AT_HANDLE_FID means there is no intention to decode file handle 121 + * AT_HANDLE_CONNECTABLE means there is an intention to decode a 122 + * connected fd (with known path), so these flags are conflicting. 123 + * AT_EMPTY_PATH could be used along with a dfd that refers to a 124 + * disconnected non-directory, which cannot be used to encode a 125 + * connectable file handle, because its parent is unknown. 126 + */ 127 + if (flag & AT_HANDLE_CONNECTABLE && 128 + flag & (AT_HANDLE_FID | AT_EMPTY_PATH)) 129 + return -EINVAL; 130 + else if (flag & AT_HANDLE_FID) 131 + fh_flags |= EXPORT_FH_FID; 132 + else if (flag & AT_HANDLE_CONNECTABLE) 133 + fh_flags |= EXPORT_FH_CONNECTABLE; 134 + 142 135 lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0; 143 - fh_flags = (flag & AT_HANDLE_FID) ? EXPORT_FH_FID : 0; 144 136 if (flag & AT_EMPTY_PATH) 145 137 lookup_flags |= LOOKUP_EMPTY; 146 138 err = user_path_at(dfd, name, lookup_flags, &path); ··· 245 207 246 208 if (!(ctx->flags & HANDLE_CHECK_SUBTREE) || d == root) 247 209 retval = 1; 248 - WARN_ON_ONCE(d != root && d != root->d_sb->s_root); 210 + /* 211 + * exportfs_decode_fh_raw() does not call acceptable() callback with 212 + * a disconnected directory dentry, so we should have reached either 213 + * mount fd directory or sb root. 214 + */ 215 + if (ctx->fh_flags & EXPORT_FH_DIR_ONLY) 216 + WARN_ON_ONCE(d != root && d != root->d_sb->s_root); 249 217 dput(d); 250 218 return retval; 251 219 } ··· 350 306 retval = -EINVAL; 351 307 goto out_path; 352 308 } 309 + if (f_handle.handle_type < 0 || 310 + FILEID_USER_FLAGS(f_handle.handle_type) & ~FILEID_VALID_USER_FLAGS) { 311 + retval = -EINVAL; 312 + goto out_path; 313 + } 314 + 353 315 handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes), 354 316 GFP_KERNEL); 355 317 if (!handle) { ··· 371 321 goto out_handle; 372 322 } 373 323 324 + /* 325 + * If handle was encoded with AT_HANDLE_CONNECTABLE, verify that we 326 + * are decoding an fd with connected path, which is accessible from 327 + * the mount fd path. 328 + */ 329 + if (f_handle.handle_type & FILEID_IS_CONNECTABLE) { 330 + ctx.fh_flags |= EXPORT_FH_CONNECTABLE; 331 + ctx.flags |= HANDLE_CHECK_SUBTREE; 332 + } 333 + if (f_handle.handle_type & FILEID_IS_DIR) 334 + ctx.fh_flags |= EXPORT_FH_DIR_ONLY; 335 + /* Filesystem code should not be exposed to user flags */ 336 + handle->handle_type &= ~FILEID_USER_FLAGS_MASK; 374 337 retval = do_handle_to_path(handle, path, &ctx); 375 338 376 339 out_handle:
+13
include/linux/exportfs.h
··· 160 160 #define EXPORT_FH_FID 0x2 /* File handle may be non-decodeable */ 161 161 #define EXPORT_FH_DIR_ONLY 0x4 /* Only decode file handle for a directory */ 162 162 163 + /* 164 + * Filesystems use only lower 8 bits of file_handle type for fid_type. 165 + * name_to_handle_at() uses upper 16 bits of type as user flags to be 166 + * interpreted by open_by_handle_at(). 167 + */ 168 + #define FILEID_USER_FLAGS_MASK 0xffff0000 169 + #define FILEID_USER_FLAGS(type) ((type) & FILEID_USER_FLAGS_MASK) 170 + 171 + /* Flags supported in encoded handle_type that is exported to user */ 172 + #define FILEID_IS_CONNECTABLE 0x10000 173 + #define FILEID_IS_DIR 0x20000 174 + #define FILEID_VALID_USER_FLAGS (FILEID_IS_CONNECTABLE | FILEID_IS_DIR) 175 + 163 176 /** 164 177 * struct export_operations - for nfsd to communicate with file systems 165 178 * @encode_fh: encode a file handle fragment from a dentry
+1
include/uapi/linux/fcntl.h
··· 153 153 object identity and may not be 154 154 usable with open_by_handle_at(2). */ 155 155 #define AT_HANDLE_MNT_ID_UNIQUE 0x001 /* Return the u64 unique mount ID. */ 156 + #define AT_HANDLE_CONNECTABLE 0x002 /* Request a connectable file handle */ 156 157 157 158 #endif /* _UAPI_LINUX_FCNTL_H */