+
+ llu_prepare_mdc_data(&op_data, dir, NULL, name, len, 0);
+ err = mdc_create(sbi->ll_md_exp, &op_data,
+ tgt, strlen(tgt) + 1, S_IFLNK | S_IRWXUGO,
+ current->fsuid, current->fsgid, 0, &request);
+ ptlrpc_req_finished(request);
+ RETURN(err);
+}
+
+static int llu_readlink_internal(struct inode *inode,
+ struct ptlrpc_request **request,
+ char **symname)
+{
+ struct llu_inode_info *lli = llu_i2info(inode);
+ struct llu_sb_info *sbi = llu_i2sbi(inode);
+ struct lustre_id id;
+ struct mds_body *body;
+ int rc, symlen = lli->lli_st_size + 1;
+ ENTRY;
+
+ *request = NULL;
+
+ if (lli->lli_symlink_name) {
+ *symname = lli->lli_symlink_name;
+ CDEBUG(D_INODE, "using cached symlink %s\n", *symname);
+ RETURN(0);
+ }
+
+ ll_inode2id(&id, inode);
+ rc = mdc_getattr(sbi->ll_md_exp, &id,
+ OBD_MD_LINKNAME, NULL, 0, symlen, request);
+ if (rc) {
+ CERROR("inode %lu: rc = %d\n", lli->lli_st_ino, rc);
+ RETURN(rc);
+ }
+
+ body = lustre_msg_buf ((*request)->rq_repmsg, 0, sizeof (*body));
+ LASSERT (body != NULL);
+ LASSERT_REPSWABBED (*request, 0);
+
+ if ((body->valid & OBD_MD_LINKNAME) == 0) {
+ CERROR ("OBD_MD_LINKNAME not set on reply\n");
+ GOTO (failed, rc = -EPROTO);
+ }
+
+ LASSERT (symlen != 0);
+ if (body->eadatasize != symlen) {
+ CERROR ("inode %lu: symlink length %d not expected %d\n",
+ lli->lli_st_ino, body->eadatasize - 1, symlen - 1);
+ GOTO (failed, rc = -EPROTO);
+ }
+
+ *symname = lustre_msg_buf ((*request)->rq_repmsg, 1, symlen);
+ if (*symname == NULL ||
+ strnlen (*symname, symlen) != symlen - 1) {
+ /* not full/NULL terminated */
+ CERROR ("inode %lu: symlink not NULL terminated string"
+ "of length %d\n", lli->lli_st_ino, symlen - 1);
+ GOTO (failed, rc = -EPROTO);
+ }
+
+ OBD_ALLOC(lli->lli_symlink_name, symlen);
+ /* do not return an error if we cannot cache the symlink locally */
+ if (lli->lli_symlink_name)
+ memcpy(lli->lli_symlink_name, *symname, symlen);
+
+ RETURN(0);
+
+ failed:
+ ptlrpc_req_finished (*request);
+ RETURN (-EPROTO);
+}
+
+static int llu_iop_readlink(struct pnode *pno, char *data, size_t bufsize)
+{
+ struct inode *inode = pno->p_base->pb_ino;
+ struct ptlrpc_request *request;
+ char *symname;
+ int rc;
+ ENTRY;
+
+ rc = llu_readlink_internal(inode, &request, &symname);
+ if (rc)
+ GOTO(out, rc);
+
+ LASSERT(symname);
+ strncpy(data, symname, bufsize);
+