+ CHECK_MOUNT_EPOCH(inode);
+
+ /* on symlinks lli_open_sem protects lli_symlink_name allocation/data */
+ down(&lli->lli_open_sem);
+ rc = ll_readlink_internal(inode, &request, &symname);
+ if (rc)
+ GOTO(out, rc);
+
+ rc = vfs_readlink(dentry, buffer, buflen, symname);
+ out:
+ up(&lli->lli_open_sem);
+ ptlrpc_free_req(request);
+
+ RETURN(rc);
+}
+
+static int ll_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+ struct inode *inode = dentry->d_inode;
+ struct ll_inode_info *lli = ll_i2info(inode);
+ struct ptlrpc_request *request;
+ char *symname;
+ int rc;
+ ENTRY;
+
+ CHECK_MOUNT_EPOCH(inode);
+
+ down(&lli->lli_open_sem);
+ rc = ll_readlink_internal(inode, &request, &symname);
+ if (rc)
+ GOTO(out, rc);
+
+ rc = vfs_follow_link(nd, symname);
+ out:
+ up(&lli->lli_open_sem);