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 (!test_bit(LL_SBI_FOREIGN_SYMLINK_UPCALL, sbi->ll_flags))
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 lmv_stripe_object *lsm_obj = NULL;
223 struct lov_foreign_md *lfm = NULL;
224 char *destname = NULL;
230 if (S_ISREG(inode->i_mode)) {
231 struct cl_object *obj = lli->lli_clob;
232 struct cl_layout cl = {
233 .cl_buf.lb_len = 0, /* to get real size */
239 CERROR("%s: inode "DFID": can not get layout, no cl_object\n",
240 sbi->ll_fsname, PFID(ll_inode2fid(inode)));
241 GOTO(failed, rc = -EINVAL);
244 env = cl_env_get(&refcheck);
246 RETURN(PTR_ERR(env));
247 /* get layout size */
248 rc = cl_object_layout_get(env, obj, &cl);
250 CERROR("%s: inode "DFID": error trying to get layout size : %d\n",
251 sbi->ll_fsname, PFID(ll_inode2fid(inode)), rc);
252 cl_env_put(env, &refcheck);
257 CERROR("%s: inode "DFID": can not allocate enough mem to get layout\n",
258 sbi->ll_fsname, PFID(ll_inode2fid(inode)));
259 cl_env_put(env, &refcheck);
262 cl.cl_buf.lb_len = rc;
263 cl.cl_buf.lb_buf = lfm;
265 rc = cl_object_layout_get(env, obj, &cl);
267 CERROR("%s: inode "DFID": error trying to get layout : %d\n",
268 sbi->ll_fsname, PFID(ll_inode2fid(inode)), rc);
269 OBD_FREE(lfm, cl.cl_buf.lb_len);
270 cl_env_put(env, &refcheck);
273 lfm_size = cl.cl_buf.lb_len;
274 cl_env_put(env, &refcheck);
275 } else if (S_ISDIR(inode->i_mode)) {
276 down_read(&lli->lli_lsm_sem);
278 /* should be casted lmv_foreign_md, but it is ok as both foreign LOV
279 * and LMV formats are identical, and then we also only need
280 * one set of parsing routines for both foreign files and dirs!
282 lsm_obj = lmv_stripe_object_get(lli->lli_lsm_obj);
283 up_read(&lli->lli_lsm_sem);
285 if (lsm_obj != NULL) {
286 lfm = (struct lov_foreign_md *)&lsm_obj->lso_lfm;
287 CDEBUG(D_INFO, "%s: inode "DFID": LMV cached found\n",
288 sbi->ll_fsname, PFID(ll_inode2fid(inode)));
290 CERROR("%s: inode "DFID": cannot get layout, no LMV cached\n",
291 sbi->ll_fsname, PFID(ll_inode2fid(inode)));
292 GOTO(failed, rc = -EINVAL);
295 CERROR("%s: inode "DFID": not a regular file nor directory\n",
296 sbi->ll_fsname, PFID(ll_inode2fid(inode)));
297 GOTO(failed, rc = -EINVAL);
300 /* XXX no assert nor double check of magic, length and type ? */
302 rc = ll_foreign_symlink_parse(sbi, inode, lfm, &destname);
305 if (S_ISDIR(inode->i_mode))
306 lmv_stripe_object_put(&lsm_obj);
308 if (S_ISREG(inode->i_mode) && lfm)
309 OBD_FREE(lfm, lfm_size);
314 "%s: inode "DFID": faking symlink to dest '%s'\n",
315 sbi->ll_fsname, PFID(ll_inode2fid(inode)), destname);
321 #ifdef HAVE_SYMLINK_OPS_USE_NAMEIDATA
322 static void ll_foreign_put_link(struct dentry *dentry,
323 struct nameidata *nd, void *cookie)
325 # ifdef HAVE_IOP_GET_LINK
326 static void ll_foreign_put_link(void *cookie)
328 static void ll_foreign_put_link(struct inode *unused, void *cookie)
332 /* to avoid allocating an unnecessary big buffer, and since ways to
333 * build the symlink path from foreign LOV/LMV can be multiple and
334 * not constant. So it size is not known and we need to use
335 * strlen(cookie)+1 to determine its size and to avoid false positive
336 * to be reported by memory leak check code
338 OBD_FREE_LARGE(cookie, strlen(cookie) + 1);
341 #ifdef HAVE_SYMLINK_OPS_USE_NAMEIDATA
342 static void *ll_foreign_follow_link(struct dentry *dentry,
343 struct nameidata *nd)
345 struct inode *inode = dentry->d_inode;
347 char *symname = NULL;
351 CDEBUG(D_VFSTRACE, "VFS Op\n");
353 * Limit the recursive symlink depth to 5 instead of default
354 * 8 links when kernel has 4k stack to prevent stack overflow.
355 * For 8k stacks we need to limit it to 7 for local servers.
357 if (THREAD_SIZE < 8192 && current->link_count >= 6)
359 else if (THREAD_SIZE == 8192 && current->link_count >= 8)
362 rc = ll_foreign_readlink_internal(inode, &symname);
365 symname = ERR_PTR(rc);
367 nd_set_link(nd, symname);
371 #elif defined(HAVE_IOP_GET_LINK)
372 static const char *ll_foreign_get_link(struct dentry *dentry,
374 struct delayed_call *done)
376 char *symname = NULL;
380 CDEBUG(D_VFSTRACE, "VFS Op\n");
382 RETURN(ERR_PTR(-ECHILD));
383 rc = ll_foreign_readlink_internal(inode, &symname);
386 * symname must be freed when we are done
388 * XXX we may avoid the need to do so if we use
389 * lli_symlink_name cache to retain symname and
390 * let ll_clear_inode free it...
392 set_delayed_call(done, ll_foreign_put_link, symname);
393 RETURN(rc ? ERR_PTR(rc) : symname);
396 # else /* !HAVE_IOP_GET_LINK */
397 static const char *ll_foreign_follow_link(struct dentry *dentry,
400 struct inode *inode = d_inode(dentry);
401 char *symname = NULL;
406 CDEBUG(D_VFSTRACE, "VFS Op\n");
407 rc = ll_foreign_readlink_internal(inode, &symname);
411 /* XXX need to also return symname in cookie in order to delay
418 #endif /* HAVE_SYMLINK_OPS_USE_NAMEIDATA, HAVE_IOP_GET_LINK */
421 * Should only be called for already in-use/cache foreign dir inode
422 * when foreign fake-symlink behaviour has been enabled afterward
424 static struct dentry *ll_foreign_dir_lookup(struct inode *parent,
425 struct dentry *dentry,
428 CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s, dir="DFID"(%p)\n",
429 dentry->d_name.len, dentry->d_name.name,
430 PFID(ll_inode2fid(parent)), parent);
432 return ERR_PTR(-ENODATA);
435 static bool has_same_mount_namespace(struct ll_sb_info *sbi)
439 same = (sbi->ll_mnt_ns == current->nsproxy->mnt_ns);
441 LCONSOLE_WARN("%s: client mount %s and '%s.%d' not in same mnt-namespace\n",
442 sbi->ll_fsname, sbi->ll_kset.kobj.name,
443 current->comm, current->pid);
448 ssize_t foreign_symlink_enable_show(struct kobject *kobj,
449 struct attribute *attr, char *buf)
451 struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
454 return snprintf(buf, PAGE_SIZE, "%d\n",
455 test_bit(LL_SBI_FOREIGN_SYMLINK, sbi->ll_flags));
460 * There should be already in-use/cached inodes of foreign files/dirs who
461 * will not-be/continue-to-be handled as fake-symlink, depending if
462 * feature is being enabled/disabled, until being revalidated.
463 * Also, does it require sbi->ll_lock protection ?
465 ssize_t foreign_symlink_enable_store(struct kobject *kobj,
466 struct attribute *attr,
467 const char *buffer, size_t count)
469 struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
474 if (!has_same_mount_namespace(sbi))
477 rc = kstrtouint(buffer, 10, &val);
482 set_bit(LL_SBI_FOREIGN_SYMLINK, sbi->ll_flags);
484 clear_bit(LL_SBI_FOREIGN_SYMLINK, sbi->ll_flags);
489 ssize_t foreign_symlink_prefix_show(struct kobject *kobj,
490 struct attribute *attr, char *buf)
492 struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
496 down_read(&sbi->ll_foreign_symlink_sem);
497 size = snprintf(buf, PAGE_SIZE, "%s\n", sbi->ll_foreign_symlink_prefix);
498 up_read(&sbi->ll_foreign_symlink_sem);
503 ssize_t foreign_symlink_prefix_store(struct kobject *kobj,
504 struct attribute *attr,
505 const char *buffer, size_t count)
507 struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
510 size_t new_len, old_len;
512 if (!has_same_mount_namespace(sbi))
515 /* XXX strip buffer of any CR/LF,space,... ?? */
517 /* check buffer looks like a valid absolute path */
518 if (*buffer != '/') {
519 CERROR("foreign symlink prefix must be an absolute path\n");
522 new_len = strnlen(buffer, count);
524 CDEBUG(D_INFO, "NUL byte found in %zu bytes\n", count);
525 if (new_len > PATH_MAX) {
526 CERROR("%s: foreign symlink prefix length %zu > PATH_MAX\n",
527 sbi->ll_fsname, new_len);
530 OBD_ALLOC(new, new_len + 1);
532 CERROR("%s: can not allocate space for foreign path prefix\n",
537 down_write(&sbi->ll_foreign_symlink_sem);
538 old_len = sbi->ll_foreign_symlink_prefix_size;
539 old = sbi->ll_foreign_symlink_prefix;
540 memcpy(new, buffer, new_len);
541 *(new + new_len) = '\0';
543 sbi->ll_foreign_symlink_prefix = new;
544 sbi->ll_foreign_symlink_prefix_size = new_len + 1;
545 up_write(&sbi->ll_foreign_symlink_sem);
548 OBD_FREE(old, old_len);
553 ssize_t foreign_symlink_upcall_show(struct kobject *kobj,
554 struct attribute *attr, char *buf)
557 struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
560 down_read(&sbi->ll_foreign_symlink_sem);
561 size = snprintf(buf, PAGE_SIZE, "%s\n", sbi->ll_foreign_symlink_upcall);
562 up_read(&sbi->ll_foreign_symlink_sem);
567 ssize_t foreign_symlink_upcall_store(struct kobject *kobj,
568 struct attribute *attr,
569 const char *buffer, size_t count)
571 struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
573 char *old = NULL, *new = NULL;
576 if (!has_same_mount_namespace(sbi))
579 /* XXX strip buffer of any CR/LF,space,... ?? */
581 /* check buffer looks like a valid absolute path */
582 if (*buffer != '/' && strcmp(buffer, "none")) {
583 CERROR("foreign symlink upcall must be an absolute path\n");
586 new_len = strnlen(buffer, count);
588 CDEBUG(D_INFO, "NULL byte found in %zu bytes\n", count);
589 if (new_len > PATH_MAX) {
590 CERROR("%s: foreign symlink upcall path length %zu > PATH_MAX\n",
591 sbi->ll_fsname, new_len);
595 OBD_ALLOC(new, new_len + 1);
597 CERROR("%s: can not allocate space for foreign symlink upcall path\n",
601 memcpy(new, buffer, new_len);
602 *(new + new_len) = '\0';
604 down_write(&sbi->ll_foreign_symlink_sem);
605 old = sbi->ll_foreign_symlink_upcall;
607 sbi->ll_foreign_symlink_upcall = new;
608 /* LL_SBI_FOREIGN_SYMLINK_UPCALL will be set by
609 * foreign_symlink_upcall_info_store() upon valid being provided
611 * XXX there is a potential race if there are multiple concurent
612 * attempts to set upcall path and execution occur in different
613 * order, we may end up using the format provided by a different
614 * upcall than the one set in ll_foreign_symlink_upcall
616 clear_bit(LL_SBI_FOREIGN_SYMLINK_UPCALL, sbi->ll_flags);
617 up_write(&sbi->ll_foreign_symlink_sem);
619 if (strcmp(new, "none")) {
622 /* sbi sysfs object name */
623 [1] = (char *)sbi->ll_kset.kobj.name,
628 [1] = "PATH=/sbin:/usr/sbin",
633 rc = call_usermodehelper(new, argv, envp, UMH_WAIT_EXEC);
635 CERROR("%s: error invoking foreign symlink upcall %s: rc %d\n",
636 sbi->ll_fsname, new, rc);
638 CDEBUG(D_INFO, "%s: invoked upcall %s\n",
639 sbi->ll_fsname, new);
643 OBD_FREE_LARGE(old, strlen(old) + 1);
648 /* foreign_symlink_upcall_info_store() stores format items in
649 * foreign_symlink_items[], and foreign_symlink_upcall_parse()
650 * uses it to parse each foreign symlink LOV/LMV EAs
652 ssize_t foreign_symlink_upcall_info_store(struct kobject *kobj,
653 struct attribute *attr,
654 const char *buffer, size_t count)
656 struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
658 struct ll_foreign_symlink_upcall_item items[MAX_NB_UPCALL_ITEMS], *item;
659 struct ll_foreign_symlink_upcall_item *new_items, *old_items;
660 size_t remaining = count;
661 int nb_items = 0, old_nb_items, i, rc = 0;
665 if (!has_same_mount_namespace(sbi))
668 /* parse buffer to check validity of infos and fill symlink format
672 if (count % sizeof(__u32) != 0) {
673 CERROR("%s: invalid size '%zu' of infos buffer returned by foreign symlink upcall\n",
674 sbi->ll_fsname, count);
678 /* evaluate number of items provided */
679 while (remaining > 0) {
680 item = (struct ll_foreign_symlink_upcall_item *)
681 &buffer[count - remaining];
682 switch (item->type) {
684 /* a constant string following */
685 if (item->size >= remaining -
686 offsetof(struct ll_foreign_symlink_upcall_item,
687 bytestring) - sizeof(item->type)) {
688 /* size of string must not overflow remaining
689 * bytes minus EOB_TYPE item
691 CERROR("%s: constant string too long in infos buffer returned by foreign symlink upcall\n",
693 GOTO(failed, rc = -EINVAL);
695 OBD_ALLOC(items[nb_items].string,
697 if (items[nb_items].string == NULL) {
698 CERROR("%s: constant string allocation has failed for constant string of size %zu\n",
699 sbi->ll_fsname, item->size);
700 GOTO(failed, rc = -ENOMEM);
702 memcpy(items[nb_items].string,
703 item->bytestring, item->size);
704 items[nb_items].size = item->size;
705 /* string items to fit on __u32 boundary */
706 remaining = remaining - STRING_ITEM_SZ(item->size);
710 /* a tuple (pos,len) following to delimit a sub-string
713 items[nb_items].pos = item->pos;
714 items[nb_items].len = item->len;
715 remaining -= POSLEN_ITEM_SZ;
719 if (remaining != sizeof(item->type)) {
720 CERROR("%s: early end of infos buffer returned by foreign symlink upcall\n",
722 GOTO(failed, rc = -EINVAL);
724 remaining -= sizeof(item->type);
727 CERROR("%s: wrong type '%u' encountered at pos %zu , with %zu remaining bytes, in infos buffer returned by foreign symlink upcall\n",
728 sbi->ll_fsname, (__u32)buffer[count - remaining],
729 count - remaining, remaining);
730 GOTO(failed, rc = -EINVAL);
733 items[nb_items].type = item->type;
735 if (nb_items >= MAX_NB_UPCALL_ITEMS) {
736 CERROR("%s: too many items in infos buffer returned by foreign symlink upcall\n",
738 GOTO(failed, rc = -EINVAL);
741 /* valid format has been provided by foreign symlink user upcall */
742 OBD_ALLOC_LARGE(new_items, nb_items *
743 sizeof(struct ll_foreign_symlink_upcall_item));
744 if (new_items == NULL) {
745 CERROR("%s: constant string allocation has failed for constant string of size %zu\n",
746 sbi->ll_fsname, nb_items *
747 sizeof(struct ll_foreign_symlink_upcall_item));
748 GOTO(failed, rc = -ENOMEM);
750 for (i = 0; i < nb_items; i++)
751 *((struct ll_foreign_symlink_upcall_item *)new_items + i) =
754 down_write(&sbi->ll_foreign_symlink_sem);
755 old_items = sbi->ll_foreign_symlink_upcall_items;
756 old_nb_items = sbi->ll_foreign_symlink_upcall_nb_items;
757 sbi->ll_foreign_symlink_upcall_items = new_items;
758 sbi->ll_foreign_symlink_upcall_nb_items = nb_items;
759 set_bit(LL_SBI_FOREIGN_SYMLINK_UPCALL, sbi->ll_flags);
760 up_write(&sbi->ll_foreign_symlink_sem);
763 if (old_items != NULL) {
764 for (i = 0 ; i < old_nb_items; i++)
765 if (old_items[i].type == STRING_TYPE)
766 OBD_FREE(old_items[i].string,
769 OBD_FREE_LARGE(old_items, old_nb_items *
770 sizeof(struct ll_foreign_symlink_upcall_item));
774 /* clean items[] and free any strings */
776 for (i = 0; i < nb_items; i++) {
777 switch (items[i].type) {
779 OBD_FREE(items[i].string, items[i].size);
780 items[i].string = NULL;
790 CERROR("%s: wrong '%u'type encountered in foreign symlink upcall items\n",
791 sbi->ll_fsname, items[i].type);
792 GOTO(failed, rc = -EINVAL);
799 RETURN(rc == 0 ? count : rc);
802 /* foreign fake-symlink version of ll_getattr() */
803 #if defined(HAVE_USER_NAMESPACE_ARG)
804 static int ll_foreign_symlink_getattr(struct mnt_idmap *map,
805 const struct path *path,
806 struct kstat *stat, u32 request_mask,
809 return ll_getattr_dentry(path->dentry, stat, request_mask, flags,
812 #elif defined(HAVE_INODEOPS_ENHANCED_GETATTR)
813 static int ll_foreign_symlink_getattr(const struct path *path,
814 struct kstat *stat, u32 request_mask,
817 return ll_getattr_dentry(path->dentry, stat, request_mask, flags,
821 static int ll_foreign_symlink_getattr(struct vfsmount *mnt, struct dentry *de,
824 return ll_getattr_dentry(de, stat, STATX_BASIC_STATS,
825 AT_STATX_SYNC_AS_STAT, true);
829 struct inode_operations ll_foreign_file_symlink_inode_operations = {
830 #ifdef HAVE_IOP_GENERIC_READLINK
831 .readlink = generic_readlink,
833 .setattr = ll_setattr,
834 #ifdef HAVE_IOP_GET_LINK
835 .get_link = ll_foreign_get_link,
837 .follow_link = ll_foreign_follow_link,
838 /* .put_link method required since need to release symlink copy buf */
839 .put_link = ll_foreign_put_link,
841 .getattr = ll_foreign_symlink_getattr,
842 .permission = ll_inode_permission,
843 #ifdef HAVE_IOP_XATTR
844 .setxattr = ll_setxattr,
845 .getxattr = ll_getxattr,
846 .removexattr = ll_removexattr,
848 .listxattr = ll_listxattr,
851 struct inode_operations ll_foreign_dir_symlink_inode_operations = {
852 .lookup = ll_foreign_dir_lookup,
853 #ifdef HAVE_IOP_GENERIC_READLINK
854 .readlink = generic_readlink,
856 .setattr = ll_setattr,
857 #ifdef HAVE_IOP_GET_LINK
858 .get_link = ll_foreign_get_link,
860 .follow_link = ll_foreign_follow_link,
861 .put_link = ll_foreign_put_link,
863 .getattr = ll_foreign_symlink_getattr,
864 .permission = ll_inode_permission,
865 #ifdef HAVE_IOP_XATTR
866 .setxattr = ll_setxattr,
867 .getxattr = ll_getxattr,
868 .removexattr = ll_removexattr,
870 .listxattr = ll_listxattr,