162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * VirtualBox Guest Shared Folders support: Regular file inode and file ops. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2006-2018 Oracle Corporation 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/mm.h> 962306a36Sopenharmony_ci#include <linux/page-flags.h> 1062306a36Sopenharmony_ci#include <linux/pagemap.h> 1162306a36Sopenharmony_ci#include <linux/highmem.h> 1262306a36Sopenharmony_ci#include <linux/sizes.h> 1362306a36Sopenharmony_ci#include "vfsmod.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistruct vboxsf_handle { 1662306a36Sopenharmony_ci u64 handle; 1762306a36Sopenharmony_ci u32 root; 1862306a36Sopenharmony_ci u32 access_flags; 1962306a36Sopenharmony_ci struct kref refcount; 2062306a36Sopenharmony_ci struct list_head head; 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct vboxsf_handle *vboxsf_create_sf_handle(struct inode *inode, 2462306a36Sopenharmony_ci u64 handle, u32 access_flags) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci struct vboxsf_inode *sf_i = VBOXSF_I(inode); 2762306a36Sopenharmony_ci struct vboxsf_handle *sf_handle; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci sf_handle = kmalloc(sizeof(*sf_handle), GFP_KERNEL); 3062306a36Sopenharmony_ci if (!sf_handle) 3162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci /* the host may have given us different attr then requested */ 3462306a36Sopenharmony_ci sf_i->force_restat = 1; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci /* init our handle struct and add it to the inode's handles list */ 3762306a36Sopenharmony_ci sf_handle->handle = handle; 3862306a36Sopenharmony_ci sf_handle->root = VBOXSF_SBI(inode->i_sb)->root; 3962306a36Sopenharmony_ci sf_handle->access_flags = access_flags; 4062306a36Sopenharmony_ci kref_init(&sf_handle->refcount); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci mutex_lock(&sf_i->handle_list_mutex); 4362306a36Sopenharmony_ci list_add(&sf_handle->head, &sf_i->handle_list); 4462306a36Sopenharmony_ci mutex_unlock(&sf_i->handle_list_mutex); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci return sf_handle; 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic int vboxsf_file_open(struct inode *inode, struct file *file) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb); 5262306a36Sopenharmony_ci struct shfl_createparms params = {}; 5362306a36Sopenharmony_ci struct vboxsf_handle *sf_handle; 5462306a36Sopenharmony_ci u32 access_flags = 0; 5562306a36Sopenharmony_ci int err; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* 5862306a36Sopenharmony_ci * We check the value of params.handle afterwards to find out if 5962306a36Sopenharmony_ci * the call succeeded or failed, as the API does not seem to cleanly 6062306a36Sopenharmony_ci * distinguish error and informational messages. 6162306a36Sopenharmony_ci * 6262306a36Sopenharmony_ci * Furthermore, we must set params.handle to SHFL_HANDLE_NIL to 6362306a36Sopenharmony_ci * make the shared folders host service use our mode parameter. 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_ci params.handle = SHFL_HANDLE_NIL; 6662306a36Sopenharmony_ci if (file->f_flags & O_CREAT) { 6762306a36Sopenharmony_ci params.create_flags |= SHFL_CF_ACT_CREATE_IF_NEW; 6862306a36Sopenharmony_ci /* 6962306a36Sopenharmony_ci * We ignore O_EXCL, as the Linux kernel seems to call create 7062306a36Sopenharmony_ci * beforehand itself, so O_EXCL should always fail. 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci if (file->f_flags & O_TRUNC) 7362306a36Sopenharmony_ci params.create_flags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS; 7462306a36Sopenharmony_ci else 7562306a36Sopenharmony_ci params.create_flags |= SHFL_CF_ACT_OPEN_IF_EXISTS; 7662306a36Sopenharmony_ci } else { 7762306a36Sopenharmony_ci params.create_flags |= SHFL_CF_ACT_FAIL_IF_NEW; 7862306a36Sopenharmony_ci if (file->f_flags & O_TRUNC) 7962306a36Sopenharmony_ci params.create_flags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci switch (file->f_flags & O_ACCMODE) { 8362306a36Sopenharmony_ci case O_RDONLY: 8462306a36Sopenharmony_ci access_flags |= SHFL_CF_ACCESS_READ; 8562306a36Sopenharmony_ci break; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci case O_WRONLY: 8862306a36Sopenharmony_ci access_flags |= SHFL_CF_ACCESS_WRITE; 8962306a36Sopenharmony_ci break; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci case O_RDWR: 9262306a36Sopenharmony_ci access_flags |= SHFL_CF_ACCESS_READWRITE; 9362306a36Sopenharmony_ci break; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci default: 9662306a36Sopenharmony_ci WARN_ON(1); 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (file->f_flags & O_APPEND) 10062306a36Sopenharmony_ci access_flags |= SHFL_CF_ACCESS_APPEND; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci params.create_flags |= access_flags; 10362306a36Sopenharmony_ci params.info.attr.mode = inode->i_mode; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci err = vboxsf_create_at_dentry(file_dentry(file), ¶ms); 10662306a36Sopenharmony_ci if (err == 0 && params.handle == SHFL_HANDLE_NIL) 10762306a36Sopenharmony_ci err = (params.result == SHFL_FILE_EXISTS) ? -EEXIST : -ENOENT; 10862306a36Sopenharmony_ci if (err) 10962306a36Sopenharmony_ci return err; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci sf_handle = vboxsf_create_sf_handle(inode, params.handle, access_flags); 11262306a36Sopenharmony_ci if (IS_ERR(sf_handle)) { 11362306a36Sopenharmony_ci vboxsf_close(sbi->root, params.handle); 11462306a36Sopenharmony_ci return PTR_ERR(sf_handle); 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci file->private_data = sf_handle; 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic void vboxsf_handle_release(struct kref *refcount) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct vboxsf_handle *sf_handle = 12462306a36Sopenharmony_ci container_of(refcount, struct vboxsf_handle, refcount); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci vboxsf_close(sf_handle->root, sf_handle->handle); 12762306a36Sopenharmony_ci kfree(sf_handle); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_civoid vboxsf_release_sf_handle(struct inode *inode, struct vboxsf_handle *sf_handle) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct vboxsf_inode *sf_i = VBOXSF_I(inode); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci mutex_lock(&sf_i->handle_list_mutex); 13562306a36Sopenharmony_ci list_del(&sf_handle->head); 13662306a36Sopenharmony_ci mutex_unlock(&sf_i->handle_list_mutex); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci kref_put(&sf_handle->refcount, vboxsf_handle_release); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic int vboxsf_file_release(struct inode *inode, struct file *file) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci /* 14462306a36Sopenharmony_ci * When a file is closed on our (the guest) side, we want any subsequent 14562306a36Sopenharmony_ci * accesses done on the host side to see all changes done from our side. 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_ci filemap_write_and_wait(inode->i_mapping); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci vboxsf_release_sf_handle(inode, file->private_data); 15062306a36Sopenharmony_ci return 0; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci/* 15462306a36Sopenharmony_ci * Write back dirty pages now, because there may not be any suitable 15562306a36Sopenharmony_ci * open files later 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_cistatic void vboxsf_vma_close(struct vm_area_struct *vma) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci filemap_write_and_wait(vma->vm_file->f_mapping); 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic const struct vm_operations_struct vboxsf_file_vm_ops = { 16362306a36Sopenharmony_ci .close = vboxsf_vma_close, 16462306a36Sopenharmony_ci .fault = filemap_fault, 16562306a36Sopenharmony_ci .map_pages = filemap_map_pages, 16662306a36Sopenharmony_ci}; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic int vboxsf_file_mmap(struct file *file, struct vm_area_struct *vma) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci int err; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci err = generic_file_mmap(file, vma); 17362306a36Sopenharmony_ci if (!err) 17462306a36Sopenharmony_ci vma->vm_ops = &vboxsf_file_vm_ops; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci return err; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* 18062306a36Sopenharmony_ci * Note that since we are accessing files on the host's filesystem, files 18162306a36Sopenharmony_ci * may always be changed underneath us by the host! 18262306a36Sopenharmony_ci * 18362306a36Sopenharmony_ci * The vboxsf API between the guest and the host does not offer any functions 18462306a36Sopenharmony_ci * to deal with this. There is no inode-generation to check for changes, no 18562306a36Sopenharmony_ci * events / callback on changes and no way to lock files. 18662306a36Sopenharmony_ci * 18762306a36Sopenharmony_ci * To avoid returning stale data when a file gets *opened* on our (the guest) 18862306a36Sopenharmony_ci * side, we do a "stat" on the host side, then compare the mtime with the 18962306a36Sopenharmony_ci * last known mtime and invalidate the page-cache if they differ. 19062306a36Sopenharmony_ci * This is done from vboxsf_inode_revalidate(). 19162306a36Sopenharmony_ci * 19262306a36Sopenharmony_ci * When reads are done through the read_iter fop, it is possible to do 19362306a36Sopenharmony_ci * further cache revalidation then, there are 3 options to deal with this: 19462306a36Sopenharmony_ci * 19562306a36Sopenharmony_ci * 1) Rely solely on the revalidation done at open time 19662306a36Sopenharmony_ci * 2) Do another "stat" and compare mtime again. Unfortunately the vboxsf 19762306a36Sopenharmony_ci * host API does not allow stat on handles, so we would need to use 19862306a36Sopenharmony_ci * file->f_path.dentry and the stat will then fail if the file was unlinked 19962306a36Sopenharmony_ci * or renamed (and there is no thing like NFS' silly-rename). So we get: 20062306a36Sopenharmony_ci * 2a) "stat" and compare mtime, on stat failure invalidate the cache 20162306a36Sopenharmony_ci * 2b) "stat" and compare mtime, on stat failure do nothing 20262306a36Sopenharmony_ci * 3) Simply always call invalidate_inode_pages2_range on the range of the read 20362306a36Sopenharmony_ci * 20462306a36Sopenharmony_ci * Currently we are keeping things KISS and using option 1. this allows 20562306a36Sopenharmony_ci * directly using generic_file_read_iter without wrapping it. 20662306a36Sopenharmony_ci * 20762306a36Sopenharmony_ci * This means that only data written on the host side before open() on 20862306a36Sopenharmony_ci * the guest side is guaranteed to be seen by the guest. If necessary 20962306a36Sopenharmony_ci * we may provide other read-cache strategies in the future and make this 21062306a36Sopenharmony_ci * configurable through a mount option. 21162306a36Sopenharmony_ci */ 21262306a36Sopenharmony_ciconst struct file_operations vboxsf_reg_fops = { 21362306a36Sopenharmony_ci .llseek = generic_file_llseek, 21462306a36Sopenharmony_ci .read_iter = generic_file_read_iter, 21562306a36Sopenharmony_ci .write_iter = generic_file_write_iter, 21662306a36Sopenharmony_ci .mmap = vboxsf_file_mmap, 21762306a36Sopenharmony_ci .open = vboxsf_file_open, 21862306a36Sopenharmony_ci .release = vboxsf_file_release, 21962306a36Sopenharmony_ci .fsync = noop_fsync, 22062306a36Sopenharmony_ci .splice_read = filemap_splice_read, 22162306a36Sopenharmony_ci}; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ciconst struct inode_operations vboxsf_reg_iops = { 22462306a36Sopenharmony_ci .getattr = vboxsf_getattr, 22562306a36Sopenharmony_ci .setattr = vboxsf_setattr 22662306a36Sopenharmony_ci}; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic int vboxsf_read_folio(struct file *file, struct folio *folio) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct page *page = &folio->page; 23162306a36Sopenharmony_ci struct vboxsf_handle *sf_handle = file->private_data; 23262306a36Sopenharmony_ci loff_t off = page_offset(page); 23362306a36Sopenharmony_ci u32 nread = PAGE_SIZE; 23462306a36Sopenharmony_ci u8 *buf; 23562306a36Sopenharmony_ci int err; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci buf = kmap(page); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci err = vboxsf_read(sf_handle->root, sf_handle->handle, off, &nread, buf); 24062306a36Sopenharmony_ci if (err == 0) { 24162306a36Sopenharmony_ci memset(&buf[nread], 0, PAGE_SIZE - nread); 24262306a36Sopenharmony_ci flush_dcache_page(page); 24362306a36Sopenharmony_ci SetPageUptodate(page); 24462306a36Sopenharmony_ci } else { 24562306a36Sopenharmony_ci SetPageError(page); 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci kunmap(page); 24962306a36Sopenharmony_ci unlock_page(page); 25062306a36Sopenharmony_ci return err; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic struct vboxsf_handle *vboxsf_get_write_handle(struct vboxsf_inode *sf_i) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct vboxsf_handle *h, *sf_handle = NULL; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci mutex_lock(&sf_i->handle_list_mutex); 25862306a36Sopenharmony_ci list_for_each_entry(h, &sf_i->handle_list, head) { 25962306a36Sopenharmony_ci if (h->access_flags == SHFL_CF_ACCESS_WRITE || 26062306a36Sopenharmony_ci h->access_flags == SHFL_CF_ACCESS_READWRITE) { 26162306a36Sopenharmony_ci kref_get(&h->refcount); 26262306a36Sopenharmony_ci sf_handle = h; 26362306a36Sopenharmony_ci break; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci mutex_unlock(&sf_i->handle_list_mutex); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci return sf_handle; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic int vboxsf_writepage(struct page *page, struct writeback_control *wbc) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct inode *inode = page->mapping->host; 27462306a36Sopenharmony_ci struct vboxsf_inode *sf_i = VBOXSF_I(inode); 27562306a36Sopenharmony_ci struct vboxsf_handle *sf_handle; 27662306a36Sopenharmony_ci loff_t off = page_offset(page); 27762306a36Sopenharmony_ci loff_t size = i_size_read(inode); 27862306a36Sopenharmony_ci u32 nwrite = PAGE_SIZE; 27962306a36Sopenharmony_ci u8 *buf; 28062306a36Sopenharmony_ci int err; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (off + PAGE_SIZE > size) 28362306a36Sopenharmony_ci nwrite = size & ~PAGE_MASK; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci sf_handle = vboxsf_get_write_handle(sf_i); 28662306a36Sopenharmony_ci if (!sf_handle) 28762306a36Sopenharmony_ci return -EBADF; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci buf = kmap(page); 29062306a36Sopenharmony_ci err = vboxsf_write(sf_handle->root, sf_handle->handle, 29162306a36Sopenharmony_ci off, &nwrite, buf); 29262306a36Sopenharmony_ci kunmap(page); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci kref_put(&sf_handle->refcount, vboxsf_handle_release); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (err == 0) { 29762306a36Sopenharmony_ci ClearPageError(page); 29862306a36Sopenharmony_ci /* mtime changed */ 29962306a36Sopenharmony_ci sf_i->force_restat = 1; 30062306a36Sopenharmony_ci } else { 30162306a36Sopenharmony_ci ClearPageUptodate(page); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci unlock_page(page); 30562306a36Sopenharmony_ci return err; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic int vboxsf_write_end(struct file *file, struct address_space *mapping, 30962306a36Sopenharmony_ci loff_t pos, unsigned int len, unsigned int copied, 31062306a36Sopenharmony_ci struct page *page, void *fsdata) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci struct inode *inode = mapping->host; 31362306a36Sopenharmony_ci struct vboxsf_handle *sf_handle = file->private_data; 31462306a36Sopenharmony_ci unsigned int from = pos & ~PAGE_MASK; 31562306a36Sopenharmony_ci u32 nwritten = len; 31662306a36Sopenharmony_ci u8 *buf; 31762306a36Sopenharmony_ci int err; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* zero the stale part of the page if we did a short copy */ 32062306a36Sopenharmony_ci if (!PageUptodate(page) && copied < len) 32162306a36Sopenharmony_ci zero_user(page, from + copied, len - copied); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci buf = kmap(page); 32462306a36Sopenharmony_ci err = vboxsf_write(sf_handle->root, sf_handle->handle, 32562306a36Sopenharmony_ci pos, &nwritten, buf + from); 32662306a36Sopenharmony_ci kunmap(page); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (err) { 32962306a36Sopenharmony_ci nwritten = 0; 33062306a36Sopenharmony_ci goto out; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* mtime changed */ 33462306a36Sopenharmony_ci VBOXSF_I(inode)->force_restat = 1; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (!PageUptodate(page) && nwritten == PAGE_SIZE) 33762306a36Sopenharmony_ci SetPageUptodate(page); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci pos += nwritten; 34062306a36Sopenharmony_ci if (pos > inode->i_size) 34162306a36Sopenharmony_ci i_size_write(inode, pos); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ciout: 34462306a36Sopenharmony_ci unlock_page(page); 34562306a36Sopenharmony_ci put_page(page); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci return nwritten; 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci/* 35162306a36Sopenharmony_ci * Note simple_write_begin does not read the page from disk on partial writes 35262306a36Sopenharmony_ci * this is ok since vboxsf_write_end only writes the written parts of the 35362306a36Sopenharmony_ci * page and it does not call SetPageUptodate for partial writes. 35462306a36Sopenharmony_ci */ 35562306a36Sopenharmony_ciconst struct address_space_operations vboxsf_reg_aops = { 35662306a36Sopenharmony_ci .read_folio = vboxsf_read_folio, 35762306a36Sopenharmony_ci .writepage = vboxsf_writepage, 35862306a36Sopenharmony_ci .dirty_folio = filemap_dirty_folio, 35962306a36Sopenharmony_ci .write_begin = simple_write_begin, 36062306a36Sopenharmony_ci .write_end = vboxsf_write_end, 36162306a36Sopenharmony_ci}; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic const char *vboxsf_get_link(struct dentry *dentry, struct inode *inode, 36462306a36Sopenharmony_ci struct delayed_call *done) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb); 36762306a36Sopenharmony_ci struct shfl_string *path; 36862306a36Sopenharmony_ci char *link; 36962306a36Sopenharmony_ci int err; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (!dentry) 37262306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci path = vboxsf_path_from_dentry(sbi, dentry); 37562306a36Sopenharmony_ci if (IS_ERR(path)) 37662306a36Sopenharmony_ci return ERR_CAST(path); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci link = kzalloc(PATH_MAX, GFP_KERNEL); 37962306a36Sopenharmony_ci if (!link) { 38062306a36Sopenharmony_ci __putname(path); 38162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci err = vboxsf_readlink(sbi->root, path, PATH_MAX, link); 38562306a36Sopenharmony_ci __putname(path); 38662306a36Sopenharmony_ci if (err) { 38762306a36Sopenharmony_ci kfree(link); 38862306a36Sopenharmony_ci return ERR_PTR(err); 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci set_delayed_call(done, kfree_link, link); 39262306a36Sopenharmony_ci return link; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ciconst struct inode_operations vboxsf_lnk_iops = { 39662306a36Sopenharmony_ci .get_link = vboxsf_get_link 39762306a36Sopenharmony_ci}; 398