4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2020 Intel Corporation.
26 * Foreign symlink implementation.
28 * Methods in this source file allow to construct a relative path from the
29 * LOV/LMV foreign content, to complement it with a prefix, and then to
30 * expose it to the VFS as a symlink destination.
31 * The default/internal mechanism simply takes the full foreign free string
32 * as the relative path, and for more complex internal formats an upcall has
33 * been implemented to provide format's details (presently just in terms of
34 * constant strings and substrings positions in EA, but this can be enhanced)
39 #include <linux/fs_struct.h>
41 #include <linux/stat.h>
42 #include <linux/version.h>
43 #define DEBUG_SUBSYSTEM S_LLITE
45 #include "llite_internal.h"
47 /* allocate space for "/<prefix>/<suffix>'\0'" and copy prefix in,
48 * returns start position for suffix in *destname
49 * must be called with ll_foreign_symlink_sem locked for read, to
50 * protect against sbi->ll_foreign_symlink_prefix change
51 * on output, provides position where to start prefix complement
53 static int foreign_symlink_alloc_and_copy_prefix(struct ll_sb_info *sbi,
58 size_t prefix_size, full_size;
62 /* allocate enough for "/<prefix>/<suffix>'\0'" */
63 prefix_size = sbi->ll_foreign_symlink_prefix_size - 1;
64 full_size = suffix_size + prefix_size + 3;
65 if (full_size > PATH_MAX) {
66 CERROR("%s: inode "DFID": resolved destination path too long\n",
67 sbi->ll_fsname, PFID(ll_inode2fid(inode)));
70 OBD_ALLOC(*destname, full_size);
71 if (*destname == NULL)
74 memcpy(*destname + 1, sbi->ll_foreign_symlink_prefix,
77 (*destname)[prefix_size + 1] = '/';
79 RETURN(prefix_size + 2);
82 /* if no upcall registered, default foreign symlink parsing method
83 * is to use the full lfm_value as a relative path to complement
86 static int ll_foreign_symlink_default_parse(struct ll_sb_info *sbi,
88 struct lov_foreign_md *lfm,
93 down_read(&sbi->ll_foreign_symlink_sem);
94 suffix_pos = foreign_symlink_alloc_and_copy_prefix(sbi, inode,
97 up_read(&sbi->ll_foreign_symlink_sem);
102 memcpy(*destname + suffix_pos, lfm->lfm_value,
104 (*destname)[suffix_pos + lfm->lfm_length] = '\0';
109 /* if an upcall has been registered, foreign symlink will be
110 * constructed as per upcall provided format
111 * presently we only support a serie of constant strings and sub-strings
112 * to be taken from lfm_value content
114 static int ll_foreign_symlink_upcall_parse(struct ll_sb_info *sbi,
116 struct lov_foreign_md *lfm,
119 int pos = 0, suffix_pos = -1, items_size = 0;
120 struct ll_foreign_symlink_upcall_item *foreign_symlink_items =
121 sbi->ll_foreign_symlink_upcall_items;
126 down_read(&sbi->ll_foreign_symlink_sem);
128 /* compute size of relative path of destination path
129 * could be done once during upcall items/infos reading
130 * and stored as new ll_sb_info field
132 for (i = 0; i < sbi->ll_foreign_symlink_upcall_nb_items; i++) {
133 switch (foreign_symlink_items[i].type) {
135 items_size += foreign_symlink_items[i].size;
138 items_size += foreign_symlink_items[i].len;
141 /* should be the last item */
144 CERROR("%s: unexpected type '%u' found in items\n",
145 sbi->ll_fsname, foreign_symlink_items[i].type);
146 GOTO(failed, rc = -EINVAL);
150 suffix_pos = foreign_symlink_alloc_and_copy_prefix(sbi, inode, destname,
153 GOTO(failed, rc = suffix_pos);
155 /* rescan foreign_symlink_items[] to create faked symlink dest path */
157 while (foreign_symlink_items[i].type != EOB_TYPE) {
158 if (foreign_symlink_items[i].type == STRING_TYPE) {
159 memcpy(*destname + suffix_pos + pos,
160 foreign_symlink_items[i].string,
161 foreign_symlink_items[i].size);
162 pos += foreign_symlink_items[i].size;
163 } else if (foreign_symlink_items[i].type == POSLEN_TYPE) {
164 if (lfm->lfm_length < foreign_symlink_items[i].pos +
165 foreign_symlink_items[i].len) {
166 CERROR("%s: "DFID" foreign EA too short to find (%u,%u) item\n",
168 PFID(ll_inode2fid(inode)),
169 foreign_symlink_items[i].pos,
170 foreign_symlink_items[i].len);
171 GOTO(failed, rc = -EINVAL);
173 memcpy(*destname + suffix_pos + pos,
174 lfm->lfm_value + foreign_symlink_items[i].pos,
175 foreign_symlink_items[i].len);
176 pos += foreign_symlink_items[i].len;
178 CERROR("%s: unexpected type '%u' found in items\n",
179 sbi->ll_fsname, foreign_symlink_items[i].type);
180 GOTO(failed, rc = -EINVAL);
185 up_read(&sbi->ll_foreign_symlink_sem);
187 if (rc != 0 && suffix_pos >= 0) {
188 OBD_FREE_LARGE(*destname, suffix_pos + items_size);
195 static int ll_foreign_symlink_parse(struct ll_sb_info *sbi,
197 struct lov_foreign_md *lfm,
202 /* if no user-land upcall registered, assuming whole free field
203 * of foreign LOV is relative path of faked symlink destination,
204 * to be completed by prefix
206 if (!(sbi->ll_flags & LL_SBI_FOREIGN_SYMLINK_UPCALL))
207 rc = ll_foreign_symlink_default_parse(sbi, inode, lfm,
209 else /* upcall is available */
210 rc = ll_foreign_symlink_upcall_parse(sbi, inode, lfm,
215 /* Don't need lli_size_mutex locked as LOV/LMV are EAs
216 * and should not be stored in data blocks
218 static int ll_foreign_readlink_internal(struct inode *inode, char **symname)
220 struct ll_inode_info *lli = ll_i2info(inode);
221 struct ll_sb_info *sbi = ll_i2sbi(inode);
222 struct lov_foreign_md *lfm = NULL;
223 char *destname = NULL;
229 if (S_ISREG(inode->i_mode)) {
230 struct cl_object *obj = lli->lli_clob;
231 struct cl_layout cl = {
232 .cl_buf.lb_len = 0, /* to get real size */
238 CERROR("%s: inode "DFID": can not get layout, no cl_object\n",
239 sbi->ll_fsname, PFID(ll_inode2fid(inode)));
240 GOTO(failed, rc = -EINVAL);
243 env = cl_env_get(&refcheck);
245 RETURN(PTR_ERR(env));
246 /* get layout size */
247 rc = cl_object_layout_get(env, obj, &cl);
249 CERROR("%s: inode "DFID": error trying to get layout size : %d\n",
250 sbi->ll_fsname, PFID(ll_inode2fid(inode)), rc);
251 cl_env_put(env, &refcheck);
256 CERROR("%s: inode "DFID": can not allocate enough mem to get layout\n",
257 sbi->ll_fsname, PFID(ll_inode2fid(inode)));
258 cl_env_put(env, &refcheck);
261 cl.cl_buf.lb_len = rc;
262 cl.cl_buf.lb_buf = lfm;
264 rc = cl_object_layout_get(env, obj, &cl);
266 CERROR("%s: inode "DFID": error trying to get layout : %d\n",
267 sbi->ll_fsname, PFID(ll_inode2fid(inode)), rc);
268 OBD_FREE(lfm, cl.cl_buf.lb_len);
269 cl_env_put(env, &refcheck);
272 lfm_size = cl.cl_buf.lb_len;
273 cl_env_put(env, &refcheck);
274 } else if (S_ISDIR(inode->i_mode)) {
275 down_read(&lli->lli_lsm_sem);
277 /* should be casted lmv_foreign_md, but it is ok as both foreign LOV
278 * and LMV formats are identical, and then we also only need
279 * one set of parsing routines for both foreign files and dirs!
281 lfm = (struct lov_foreign_md *)(lli->lli_lsm_md);
283 CDEBUG(D_INFO, "%s: inode "DFID": LMV cached found\n",
284 sbi->ll_fsname, PFID(ll_inode2fid(inode)));
286 CERROR("%s: inode "DFID": cannot get layout, no LMV cached\n",
287 sbi->ll_fsname, PFID(ll_inode2fid(inode)));
288 GOTO(failed, rc = -EINVAL);
291 CERROR("%s: inode "DFID": not a regular file nor directory\n",
292 sbi->ll_fsname, PFID(ll_inode2fid(inode)));
293 GOTO(failed, rc = -EINVAL);
296 /* XXX no assert nor double check of magic, length and type ? */
298 rc = ll_foreign_symlink_parse(sbi, inode, lfm, &destname);
301 if (S_ISDIR(inode->i_mode))
302 up_read(&lli->lli_lsm_sem);
304 if (S_ISREG(inode->i_mode) && lfm)
305 OBD_FREE(lfm, lfm_size);
310 "%s: inode "DFID": faking symlink to dest '%s'\n",
311 sbi->ll_fsname, PFID(ll_inode2fid(inode)), destname);
317 #ifdef HAVE_SYMLINK_OPS_USE_NAMEIDATA
318 static void ll_foreign_put_link(struct dentry *dentry,
319 struct nameidata *nd, void *cookie)
321 # ifdef HAVE_IOP_GET_LINK
322 static void ll_foreign_put_link(void *cookie)
324 static void ll_foreign_put_link(struct inode *unused, void *cookie)
328 /* to avoid allocating an unnecessary big buffer, and since ways to
329 * build the symlink path from foreign LOV/LMV can be multiple and
330 * not constant. So it size is not known and we need to use
331 * strlen(cookie)+1 to determine its size and to avoid false positive
332 * to be reported by memory leak check code
334 OBD_FREE_LARGE(cookie, strlen(cookie) + 1);
337 #ifdef HAVE_SYMLINK_OPS_USE_NAMEIDATA
338 static void *ll_foreign_follow_link(struct dentry *dentry,
339 struct nameidata *nd)
341 struct inode *inode = dentry->d_inode;
343 char *symname = NULL;
347 CDEBUG(D_VFSTRACE, "VFS Op\n");
349 * Limit the recursive symlink depth to 5 instead of default
350 * 8 links when kernel has 4k stack to prevent stack overflow.
351 * For 8k stacks we need to limit it to 7 for local servers.
353 if (THREAD_SIZE < 8192 && current->link_count >= 6)
355 else if (THREAD_SIZE == 8192 && current->link_count >= 8)
358 rc = ll_foreign_readlink_internal(inode, &symname);
361 symname = ERR_PTR(rc);
363 nd_set_link(nd, symname);
367 #elif defined(HAVE_IOP_GET_LINK)
368 static const char *ll_foreign_get_link(struct dentry *dentry,
370 struct delayed_call *done)
372 char *symname = NULL;
376 CDEBUG(D_VFSTRACE, "VFS Op\n");
378 RETURN(ERR_PTR(-ECHILD));
379 rc = ll_foreign_readlink_internal(inode, &symname);
382 * symname must be freed when we are done
384 * XXX we may avoid the need to do so if we use
385 * lli_symlink_name cache to retain symname and
386 * let ll_clear_inode free it...
388 set_delayed_call(done, ll_foreign_put_link, symname);
389 RETURN(rc ? ERR_PTR(rc) : symname);
392 # else /* !HAVE_IOP_GET_LINK */
393 static const char *ll_foreign_follow_link(struct dentry *dentry,
396 struct inode *inode = d_inode(dentry);
397 char *symname = NULL;
402 CDEBUG(D_VFSTRACE, "VFS Op\n");
403 rc = ll_foreign_readlink_internal(inode, &symname);
407 /* XXX need to also return symname in cookie in order to delay
414 #endif /* HAVE_SYMLINK_OPS_USE_NAMEIDATA, HAVE_IOP_GET_LINK */
417 * Should only be called for already in-use/cache foreign dir inode
418 * when foreign fake-symlink behaviour has been enabled afterward
420 static struct dentry *ll_foreign_dir_lookup(struct inode *parent,
421 struct dentry *dentry,
424 CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s, dir="DFID"(%p)\n",
425 dentry->d_name.len, dentry->d_name.name,
426 PFID(ll_inode2fid(parent)), parent);
428 return ERR_PTR(-ENODATA);
431 static bool has_same_mount_namespace(struct ll_sb_info *sbi)
435 rc = (sbi->ll_mnt.mnt == current->fs->root.mnt);
437 LCONSOLE_WARN("%s: client mount %s and '%s.%d' not in same mnt-namespace\n",
438 sbi->ll_fsname, sbi->ll_kset.kobj.name,
439 current->comm, current->pid);
444 ssize_t foreign_symlink_enable_show(struct kobject *kobj,
445 struct attribute *attr, char *buf)
447 struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
450 return snprintf(buf, PAGE_SIZE, "%d\n",
451 !!(sbi->ll_flags & LL_SBI_FOREIGN_SYMLINK));
456 * There should be already in-use/cached inodes of foreign files/dirs who
457 * will not-be/continue-to-be handled as fake-symlink, depending if
458 * feature is being enabled/disabled, until being revalidated.
459 * Also, does it require sbi->ll_lock protection ?
461 ssize_t foreign_symlink_enable_store(struct kobject *kobj,
462 struct attribute *attr,
463 const char *buffer, size_t count)
465 struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
470 if (!has_same_mount_namespace(sbi))
473 rc = kstrtouint(buffer, 10, &val);
478 sbi->ll_flags |= LL_SBI_FOREIGN_SYMLINK;
480 sbi->ll_flags &= ~LL_SBI_FOREIGN_SYMLINK;
485 ssize_t foreign_symlink_prefix_show(struct kobject *kobj,
486 struct attribute *attr, char *buf)
488 struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
492 down_read(&sbi->ll_foreign_symlink_sem);
493 size = snprintf(buf, PAGE_SIZE, "%s\n", sbi->ll_foreign_symlink_prefix);
494 up_read(&sbi->ll_foreign_symlink_sem);
499 ssize_t foreign_symlink_prefix_store(struct kobject *kobj,
500 struct attribute *attr,
501 const char *buffer, size_t count)
503 struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
506 size_t new_len, old_len;
508 if (!has_same_mount_namespace(sbi))
511 /* XXX strip buffer of any CR/LF,space,... ?? */
513 /* check buffer looks like a valid absolute path */
514 if (*buffer != '/') {
515 CERROR("foreign symlink prefix must be an absolute path\n");
518 new_len = strnlen(buffer, count);
520 CDEBUG(D_INFO, "NUL byte found in %zu bytes\n", count);
521 if (new_len > PATH_MAX) {
522 CERROR("%s: foreign symlink prefix length %zu > PATH_MAX\n",
523 sbi->ll_fsname, new_len);
526 OBD_ALLOC(new, new_len + 1);
528 CERROR("%s: can not allocate space for foreign path prefix\n",
533 down_write(&sbi->ll_foreign_symlink_sem);
534 old_len = sbi->ll_foreign_symlink_prefix_size;
535 old = sbi->ll_foreign_symlink_prefix;
536 memcpy(new, buffer, new_len);
537 *(new + new_len) = '\0';
539 sbi->ll_foreign_symlink_prefix = new;
540 sbi->ll_foreign_symlink_prefix_size = new_len + 1;
541 up_write(&sbi->ll_foreign_symlink_sem);
544 OBD_FREE(old, old_len);
549 ssize_t foreign_symlink_upcall_show(struct kobject *kobj,
550 struct attribute *attr, char *buf)
553 struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
556 down_read(&sbi->ll_foreign_symlink_sem);
557 size = snprintf(buf, PAGE_SIZE, "%s\n", sbi->ll_foreign_symlink_upcall);
558 up_read(&sbi->ll_foreign_symlink_sem);
563 ssize_t foreign_symlink_upcall_store(struct kobject *kobj,
564 struct attribute *attr,
565 const char *buffer, size_t count)
567 struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
569 char *old = NULL, *new = NULL;
572 if (!has_same_mount_namespace(sbi))
575 /* XXX strip buffer of any CR/LF,space,... ?? */
577 /* check buffer looks like a valid absolute path */
578 if (*buffer != '/' && strcmp(buffer, "none")) {
579 CERROR("foreign symlink upcall must be an absolute path\n");
582 new_len = strnlen(buffer, count);
584 CDEBUG(D_INFO, "NULL byte found in %zu bytes\n", count);
585 if (new_len > PATH_MAX) {
586 CERROR("%s: foreign symlink upcall path length %zu > PATH_MAX\n",
587 sbi->ll_fsname, new_len);
591 OBD_ALLOC(new, new_len + 1);
593 CERROR("%s: can not allocate space for foreign symlink upcall path\n",
597 memcpy(new, buffer, new_len);
598 *(new + new_len) = '\0';
600 down_write(&sbi->ll_foreign_symlink_sem);
601 old = sbi->ll_foreign_symlink_upcall;
603 sbi->ll_foreign_symlink_upcall = new;
604 /* LL_SBI_FOREIGN_SYMLINK_UPCALL will be set by
605 * foreign_symlink_upcall_info_store() upon valid being provided
607 * XXX there is a potential race if there are multiple concurent
608 * attempts to set upcall path and execution occur in different
609 * order, we may end up using the format provided by a different
610 * upcall than the one set in ll_foreign_symlink_upcall
612 sbi->ll_flags &= ~LL_SBI_FOREIGN_SYMLINK_UPCALL;
613 up_write(&sbi->ll_foreign_symlink_sem);
615 if (strcmp(new, "none")) {
618 /* sbi sysfs object name */
619 [1] = (char *)sbi->ll_kset.kobj.name,
624 [1] = "PATH=/sbin:/usr/sbin",
629 rc = call_usermodehelper(new, argv, envp, UMH_WAIT_EXEC);
631 CERROR("%s: error invoking foreign symlink upcall %s: rc %d\n",
632 sbi->ll_fsname, new, rc);
634 CDEBUG(D_INFO, "%s: invoked upcall %s\n",
635 sbi->ll_fsname, new);
639 OBD_FREE_LARGE(old, strlen(old) + 1);
644 /* foreign_symlink_upcall_info_store() stores format items in
645 * foreign_symlink_items[], and foreign_symlink_upcall_parse()
646 * uses it to parse each foreign symlink LOV/LMV EAs
648 ssize_t foreign_symlink_upcall_info_store(struct kobject *kobj,
649 struct attribute *attr,
650 const char *buffer, size_t count)
652 struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
654 struct ll_foreign_symlink_upcall_item items[MAX_NB_UPCALL_ITEMS], *item;
655 struct ll_foreign_symlink_upcall_item *new_items, *old_items;
656 size_t remaining = count;
657 int nb_items = 0, old_nb_items, i, rc = 0;
661 if (!has_same_mount_namespace(sbi))
664 /* parse buffer to check validity of infos and fill symlink format
668 if (count % sizeof(__u32) != 0) {
669 CERROR("%s: invalid size '%zu' of infos buffer returned by foreign symlink upcall\n",
670 sbi->ll_fsname, count);
674 /* evaluate number of items provided */
675 while (remaining > 0) {
676 item = (struct ll_foreign_symlink_upcall_item *)
677 &buffer[count - remaining];
678 switch (item->type) {
680 /* a constant string following */
681 if (item->size >= remaining -
682 offsetof(struct ll_foreign_symlink_upcall_item,
683 bytestring) - sizeof(item->type)) {
684 /* size of string must not overflow remaining
685 * bytes minus EOB_TYPE item
687 CERROR("%s: constant string too long in infos buffer returned by foreign symlink upcall\n",
689 GOTO(failed, rc = -EINVAL);
691 OBD_ALLOC(items[nb_items].string,
693 if (items[nb_items].string == NULL) {
694 CERROR("%s: constant string allocation has failed for constant string of size %zu\n",
695 sbi->ll_fsname, item->size);
696 GOTO(failed, rc = -ENOMEM);
698 memcpy(items[nb_items].string,
699 item->bytestring, item->size);
700 items[nb_items].size = item->size;
701 /* string items to fit on __u32 boundary */
702 remaining = remaining - STRING_ITEM_SZ(item->size);
706 /* a tuple (pos,len) following to delimit a sub-string
709 items[nb_items].pos = item->pos;
710 items[nb_items].len = item->len;
711 remaining -= POSLEN_ITEM_SZ;
715 if (remaining != sizeof(item->type)) {
716 CERROR("%s: early end of infos buffer returned by foreign symlink upcall\n",
718 GOTO(failed, rc = -EINVAL);
720 remaining -= sizeof(item->type);
723 CERROR("%s: wrong type '%u' encountered at pos %zu , with %zu remaining bytes, in infos buffer returned by foreign symlink upcall\n",
724 sbi->ll_fsname, (__u32)buffer[count - remaining],
725 count - remaining, remaining);
726 GOTO(failed, rc = -EINVAL);
729 items[nb_items].type = item->type;
731 if (nb_items >= MAX_NB_UPCALL_ITEMS) {
732 CERROR("%s: too many items in infos buffer returned by foreign symlink upcall\n",
734 GOTO(failed, rc = -EINVAL);
737 /* valid format has been provided by foreign symlink user upcall */
738 OBD_ALLOC_LARGE(new_items, nb_items *
739 sizeof(struct ll_foreign_symlink_upcall_item));
740 if (new_items == NULL) {
741 CERROR("%s: constant string allocation has failed for constant string of size %zu\n",
742 sbi->ll_fsname, nb_items *
743 sizeof(struct ll_foreign_symlink_upcall_item));
744 GOTO(failed, rc = -ENOMEM);
746 for (i = 0; i < nb_items; i++)
747 *((struct ll_foreign_symlink_upcall_item *)new_items + i) =
750 down_write(&sbi->ll_foreign_symlink_sem);
751 old_items = sbi->ll_foreign_symlink_upcall_items;
752 old_nb_items = sbi->ll_foreign_symlink_upcall_nb_items;
753 sbi->ll_foreign_symlink_upcall_items = new_items;
754 sbi->ll_foreign_symlink_upcall_nb_items = nb_items;
755 sbi->ll_flags |= LL_SBI_FOREIGN_SYMLINK_UPCALL;
756 up_write(&sbi->ll_foreign_symlink_sem);
759 if (old_items != NULL) {
760 for (i = 0 ; i < old_nb_items; i++)
761 if (old_items[i].type == STRING_TYPE)
762 OBD_FREE(old_items[i].string,
765 OBD_FREE_LARGE(old_items, old_nb_items *
766 sizeof(struct ll_foreign_symlink_upcall_item));
770 /* clean items[] and free any strings */
772 for (i = 0; i < nb_items; i++) {
773 switch (items[i].type) {
775 OBD_FREE(items[i].string, items[i].size);
776 items[i].string = NULL;
786 CERROR("%s: wrong '%u'type encountered in foreign symlink upcall items\n",
787 sbi->ll_fsname, items[i].type);
788 GOTO(failed, rc = -EINVAL);
795 RETURN(rc == 0 ? count : rc);
798 struct inode_operations ll_foreign_file_symlink_inode_operations = {
799 #ifdef HAVE_IOP_GENERIC_READLINK
800 .readlink = generic_readlink,
802 .setattr = ll_setattr,
803 #ifdef HAVE_IOP_GET_LINK
804 .get_link = ll_foreign_get_link,
806 .follow_link = ll_foreign_follow_link,
807 /* .put_link method required since need to release symlink copy buf */
808 .put_link = ll_foreign_put_link,
810 .getattr = ll_foreign_symlink_getattr,
811 .permission = ll_inode_permission,
812 #ifdef HAVE_IOP_XATTR
813 .setxattr = ll_setxattr,
814 .getxattr = ll_getxattr,
815 .removexattr = ll_removexattr,
817 .listxattr = ll_listxattr,
820 struct inode_operations ll_foreign_dir_symlink_inode_operations = {
821 .lookup = ll_foreign_dir_lookup,
822 #ifdef HAVE_IOP_GENERIC_READLINK
823 .readlink = generic_readlink,
825 .setattr = ll_setattr,
826 #ifdef HAVE_IOP_GET_LINK
827 .get_link = ll_foreign_get_link,
829 .follow_link = ll_foreign_follow_link,
830 .put_link = ll_foreign_put_link,
832 .getattr = ll_foreign_symlink_getattr,
833 .permission = ll_inode_permission,
834 #ifdef HAVE_IOP_XATTR
835 .setxattr = ll_setxattr,
836 .getxattr = ll_getxattr,
837 .removexattr = ll_removexattr,
839 .listxattr = ll_listxattr,
842 /* foreign fake-symlink version of ll_getattr() */
843 #ifdef HAVE_INODEOPS_ENHANCED_GETATTR
844 int ll_foreign_symlink_getattr(const struct path *path, struct kstat *stat,
845 u32 request_mask, unsigned int flags)
847 return ll_getattr_dentry(path->dentry, stat, request_mask, flags,
851 int ll_foreign_symlink_getattr(struct vfsmount *mnt, struct dentry *de,
854 return ll_getattr_dentry(de, stat, STATX_BASIC_STATS,
855 AT_STATX_SYNC_AS_STAT, true);