162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * (C) 2001 Clemson University and The University of Chicago 462306a36Sopenharmony_ci * Copyright 2018 Omnibond Systems, L.L.C. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * See COPYING in top-level directory. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci/* 1062306a36Sopenharmony_ci * Linux VFS inode operations. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/blkdev.h> 1462306a36Sopenharmony_ci#include <linux/fileattr.h> 1562306a36Sopenharmony_ci#include "protocol.h" 1662306a36Sopenharmony_ci#include "orangefs-kernel.h" 1762306a36Sopenharmony_ci#include "orangefs-bufmap.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic int orangefs_writepage_locked(struct page *page, 2062306a36Sopenharmony_ci struct writeback_control *wbc) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci struct inode *inode = page->mapping->host; 2362306a36Sopenharmony_ci struct orangefs_write_range *wr = NULL; 2462306a36Sopenharmony_ci struct iov_iter iter; 2562306a36Sopenharmony_ci struct bio_vec bv; 2662306a36Sopenharmony_ci size_t len, wlen; 2762306a36Sopenharmony_ci ssize_t ret; 2862306a36Sopenharmony_ci loff_t off; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci set_page_writeback(page); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci len = i_size_read(inode); 3362306a36Sopenharmony_ci if (PagePrivate(page)) { 3462306a36Sopenharmony_ci wr = (struct orangefs_write_range *)page_private(page); 3562306a36Sopenharmony_ci WARN_ON(wr->pos >= len); 3662306a36Sopenharmony_ci off = wr->pos; 3762306a36Sopenharmony_ci if (off + wr->len > len) 3862306a36Sopenharmony_ci wlen = len - off; 3962306a36Sopenharmony_ci else 4062306a36Sopenharmony_ci wlen = wr->len; 4162306a36Sopenharmony_ci } else { 4262306a36Sopenharmony_ci WARN_ON(1); 4362306a36Sopenharmony_ci off = page_offset(page); 4462306a36Sopenharmony_ci if (off + PAGE_SIZE > len) 4562306a36Sopenharmony_ci wlen = len - off; 4662306a36Sopenharmony_ci else 4762306a36Sopenharmony_ci wlen = PAGE_SIZE; 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci /* Should've been handled in orangefs_invalidate_folio. */ 5062306a36Sopenharmony_ci WARN_ON(off == len || off + wlen > len); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci WARN_ON(wlen == 0); 5362306a36Sopenharmony_ci bvec_set_page(&bv, page, wlen, off % PAGE_SIZE); 5462306a36Sopenharmony_ci iov_iter_bvec(&iter, ITER_SOURCE, &bv, 1, wlen); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci ret = wait_for_direct_io(ORANGEFS_IO_WRITE, inode, &off, &iter, wlen, 5762306a36Sopenharmony_ci len, wr, NULL, NULL); 5862306a36Sopenharmony_ci if (ret < 0) { 5962306a36Sopenharmony_ci SetPageError(page); 6062306a36Sopenharmony_ci mapping_set_error(page->mapping, ret); 6162306a36Sopenharmony_ci } else { 6262306a36Sopenharmony_ci ret = 0; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci kfree(detach_page_private(page)); 6562306a36Sopenharmony_ci return ret; 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic int orangefs_writepage(struct page *page, struct writeback_control *wbc) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci int ret; 7162306a36Sopenharmony_ci ret = orangefs_writepage_locked(page, wbc); 7262306a36Sopenharmony_ci unlock_page(page); 7362306a36Sopenharmony_ci end_page_writeback(page); 7462306a36Sopenharmony_ci return ret; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistruct orangefs_writepages { 7862306a36Sopenharmony_ci loff_t off; 7962306a36Sopenharmony_ci size_t len; 8062306a36Sopenharmony_ci kuid_t uid; 8162306a36Sopenharmony_ci kgid_t gid; 8262306a36Sopenharmony_ci int maxpages; 8362306a36Sopenharmony_ci int npages; 8462306a36Sopenharmony_ci struct page **pages; 8562306a36Sopenharmony_ci struct bio_vec *bv; 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic int orangefs_writepages_work(struct orangefs_writepages *ow, 8962306a36Sopenharmony_ci struct writeback_control *wbc) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct inode *inode = ow->pages[0]->mapping->host; 9262306a36Sopenharmony_ci struct orangefs_write_range *wrp, wr; 9362306a36Sopenharmony_ci struct iov_iter iter; 9462306a36Sopenharmony_ci ssize_t ret; 9562306a36Sopenharmony_ci size_t len; 9662306a36Sopenharmony_ci loff_t off; 9762306a36Sopenharmony_ci int i; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci len = i_size_read(inode); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci for (i = 0; i < ow->npages; i++) { 10262306a36Sopenharmony_ci set_page_writeback(ow->pages[i]); 10362306a36Sopenharmony_ci bvec_set_page(&ow->bv[i], ow->pages[i], 10462306a36Sopenharmony_ci min(page_offset(ow->pages[i]) + PAGE_SIZE, 10562306a36Sopenharmony_ci ow->off + ow->len) - 10662306a36Sopenharmony_ci max(ow->off, page_offset(ow->pages[i])), 10762306a36Sopenharmony_ci i == 0 ? ow->off - page_offset(ow->pages[i]) : 0); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci iov_iter_bvec(&iter, ITER_SOURCE, ow->bv, ow->npages, ow->len); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci WARN_ON(ow->off >= len); 11262306a36Sopenharmony_ci if (ow->off + ow->len > len) 11362306a36Sopenharmony_ci ow->len = len - ow->off; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci off = ow->off; 11662306a36Sopenharmony_ci wr.uid = ow->uid; 11762306a36Sopenharmony_ci wr.gid = ow->gid; 11862306a36Sopenharmony_ci ret = wait_for_direct_io(ORANGEFS_IO_WRITE, inode, &off, &iter, ow->len, 11962306a36Sopenharmony_ci 0, &wr, NULL, NULL); 12062306a36Sopenharmony_ci if (ret < 0) { 12162306a36Sopenharmony_ci for (i = 0; i < ow->npages; i++) { 12262306a36Sopenharmony_ci SetPageError(ow->pages[i]); 12362306a36Sopenharmony_ci mapping_set_error(ow->pages[i]->mapping, ret); 12462306a36Sopenharmony_ci if (PagePrivate(ow->pages[i])) { 12562306a36Sopenharmony_ci wrp = (struct orangefs_write_range *) 12662306a36Sopenharmony_ci page_private(ow->pages[i]); 12762306a36Sopenharmony_ci ClearPagePrivate(ow->pages[i]); 12862306a36Sopenharmony_ci put_page(ow->pages[i]); 12962306a36Sopenharmony_ci kfree(wrp); 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci end_page_writeback(ow->pages[i]); 13262306a36Sopenharmony_ci unlock_page(ow->pages[i]); 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci } else { 13562306a36Sopenharmony_ci ret = 0; 13662306a36Sopenharmony_ci for (i = 0; i < ow->npages; i++) { 13762306a36Sopenharmony_ci if (PagePrivate(ow->pages[i])) { 13862306a36Sopenharmony_ci wrp = (struct orangefs_write_range *) 13962306a36Sopenharmony_ci page_private(ow->pages[i]); 14062306a36Sopenharmony_ci ClearPagePrivate(ow->pages[i]); 14162306a36Sopenharmony_ci put_page(ow->pages[i]); 14262306a36Sopenharmony_ci kfree(wrp); 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci end_page_writeback(ow->pages[i]); 14562306a36Sopenharmony_ci unlock_page(ow->pages[i]); 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci return ret; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic int orangefs_writepages_callback(struct folio *folio, 15262306a36Sopenharmony_ci struct writeback_control *wbc, void *data) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct orangefs_writepages *ow = data; 15562306a36Sopenharmony_ci struct orangefs_write_range *wr = folio->private; 15662306a36Sopenharmony_ci int ret; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (!wr) { 15962306a36Sopenharmony_ci folio_unlock(folio); 16062306a36Sopenharmony_ci /* It's not private so there's nothing to write, right? */ 16162306a36Sopenharmony_ci printk("writepages_callback not private!\n"); 16262306a36Sopenharmony_ci BUG(); 16362306a36Sopenharmony_ci return 0; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci ret = -1; 16762306a36Sopenharmony_ci if (ow->npages == 0) { 16862306a36Sopenharmony_ci ow->off = wr->pos; 16962306a36Sopenharmony_ci ow->len = wr->len; 17062306a36Sopenharmony_ci ow->uid = wr->uid; 17162306a36Sopenharmony_ci ow->gid = wr->gid; 17262306a36Sopenharmony_ci ow->pages[ow->npages++] = &folio->page; 17362306a36Sopenharmony_ci ret = 0; 17462306a36Sopenharmony_ci goto done; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci if (!uid_eq(ow->uid, wr->uid) || !gid_eq(ow->gid, wr->gid)) { 17762306a36Sopenharmony_ci orangefs_writepages_work(ow, wbc); 17862306a36Sopenharmony_ci ow->npages = 0; 17962306a36Sopenharmony_ci ret = -1; 18062306a36Sopenharmony_ci goto done; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci if (ow->off + ow->len == wr->pos) { 18362306a36Sopenharmony_ci ow->len += wr->len; 18462306a36Sopenharmony_ci ow->pages[ow->npages++] = &folio->page; 18562306a36Sopenharmony_ci ret = 0; 18662306a36Sopenharmony_ci goto done; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_cidone: 18962306a36Sopenharmony_ci if (ret == -1) { 19062306a36Sopenharmony_ci if (ow->npages) { 19162306a36Sopenharmony_ci orangefs_writepages_work(ow, wbc); 19262306a36Sopenharmony_ci ow->npages = 0; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci ret = orangefs_writepage_locked(&folio->page, wbc); 19562306a36Sopenharmony_ci mapping_set_error(folio->mapping, ret); 19662306a36Sopenharmony_ci folio_unlock(folio); 19762306a36Sopenharmony_ci folio_end_writeback(folio); 19862306a36Sopenharmony_ci } else { 19962306a36Sopenharmony_ci if (ow->npages == ow->maxpages) { 20062306a36Sopenharmony_ci orangefs_writepages_work(ow, wbc); 20162306a36Sopenharmony_ci ow->npages = 0; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci return ret; 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic int orangefs_writepages(struct address_space *mapping, 20862306a36Sopenharmony_ci struct writeback_control *wbc) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct orangefs_writepages *ow; 21162306a36Sopenharmony_ci struct blk_plug plug; 21262306a36Sopenharmony_ci int ret; 21362306a36Sopenharmony_ci ow = kzalloc(sizeof(struct orangefs_writepages), GFP_KERNEL); 21462306a36Sopenharmony_ci if (!ow) 21562306a36Sopenharmony_ci return -ENOMEM; 21662306a36Sopenharmony_ci ow->maxpages = orangefs_bufmap_size_query()/PAGE_SIZE; 21762306a36Sopenharmony_ci ow->pages = kcalloc(ow->maxpages, sizeof(struct page *), GFP_KERNEL); 21862306a36Sopenharmony_ci if (!ow->pages) { 21962306a36Sopenharmony_ci kfree(ow); 22062306a36Sopenharmony_ci return -ENOMEM; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci ow->bv = kcalloc(ow->maxpages, sizeof(struct bio_vec), GFP_KERNEL); 22362306a36Sopenharmony_ci if (!ow->bv) { 22462306a36Sopenharmony_ci kfree(ow->pages); 22562306a36Sopenharmony_ci kfree(ow); 22662306a36Sopenharmony_ci return -ENOMEM; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci blk_start_plug(&plug); 22962306a36Sopenharmony_ci ret = write_cache_pages(mapping, wbc, orangefs_writepages_callback, ow); 23062306a36Sopenharmony_ci if (ow->npages) 23162306a36Sopenharmony_ci ret = orangefs_writepages_work(ow, wbc); 23262306a36Sopenharmony_ci blk_finish_plug(&plug); 23362306a36Sopenharmony_ci kfree(ow->pages); 23462306a36Sopenharmony_ci kfree(ow->bv); 23562306a36Sopenharmony_ci kfree(ow); 23662306a36Sopenharmony_ci return ret; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int orangefs_launder_folio(struct folio *); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic void orangefs_readahead(struct readahead_control *rac) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci loff_t offset; 24462306a36Sopenharmony_ci struct iov_iter iter; 24562306a36Sopenharmony_ci struct inode *inode = rac->mapping->host; 24662306a36Sopenharmony_ci struct xarray *i_pages; 24762306a36Sopenharmony_ci struct folio *folio; 24862306a36Sopenharmony_ci loff_t new_start = readahead_pos(rac); 24962306a36Sopenharmony_ci int ret; 25062306a36Sopenharmony_ci size_t new_len = 0; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci loff_t bytes_remaining = inode->i_size - readahead_pos(rac); 25362306a36Sopenharmony_ci loff_t pages_remaining = bytes_remaining / PAGE_SIZE; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (pages_remaining >= 1024) 25662306a36Sopenharmony_ci new_len = 4194304; 25762306a36Sopenharmony_ci else if (pages_remaining > readahead_count(rac)) 25862306a36Sopenharmony_ci new_len = bytes_remaining; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (new_len) 26162306a36Sopenharmony_ci readahead_expand(rac, new_start, new_len); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci offset = readahead_pos(rac); 26462306a36Sopenharmony_ci i_pages = &rac->mapping->i_pages; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci iov_iter_xarray(&iter, ITER_DEST, i_pages, offset, readahead_length(rac)); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* read in the pages. */ 26962306a36Sopenharmony_ci if ((ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, 27062306a36Sopenharmony_ci &offset, &iter, readahead_length(rac), 27162306a36Sopenharmony_ci inode->i_size, NULL, NULL, rac->file)) < 0) 27262306a36Sopenharmony_ci gossip_debug(GOSSIP_FILE_DEBUG, 27362306a36Sopenharmony_ci "%s: wait_for_direct_io failed. \n", __func__); 27462306a36Sopenharmony_ci else 27562306a36Sopenharmony_ci ret = 0; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* clean up. */ 27862306a36Sopenharmony_ci while ((folio = readahead_folio(rac))) { 27962306a36Sopenharmony_ci if (!ret) 28062306a36Sopenharmony_ci folio_mark_uptodate(folio); 28162306a36Sopenharmony_ci folio_unlock(folio); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic int orangefs_read_folio(struct file *file, struct folio *folio) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct inode *inode = folio->mapping->host; 28862306a36Sopenharmony_ci struct iov_iter iter; 28962306a36Sopenharmony_ci struct bio_vec bv; 29062306a36Sopenharmony_ci ssize_t ret; 29162306a36Sopenharmony_ci loff_t off; /* offset of this folio in the file */ 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (folio_test_dirty(folio)) 29462306a36Sopenharmony_ci orangefs_launder_folio(folio); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci off = folio_pos(folio); 29762306a36Sopenharmony_ci bvec_set_folio(&bv, folio, folio_size(folio), 0); 29862306a36Sopenharmony_ci iov_iter_bvec(&iter, ITER_DEST, &bv, 1, folio_size(folio)); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, &off, &iter, 30162306a36Sopenharmony_ci folio_size(folio), inode->i_size, NULL, NULL, file); 30262306a36Sopenharmony_ci /* this will only zero remaining unread portions of the folio data */ 30362306a36Sopenharmony_ci iov_iter_zero(~0U, &iter); 30462306a36Sopenharmony_ci /* takes care of potential aliasing */ 30562306a36Sopenharmony_ci flush_dcache_folio(folio); 30662306a36Sopenharmony_ci if (ret < 0) { 30762306a36Sopenharmony_ci folio_set_error(folio); 30862306a36Sopenharmony_ci } else { 30962306a36Sopenharmony_ci folio_mark_uptodate(folio); 31062306a36Sopenharmony_ci ret = 0; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci /* unlock the folio after the ->read_folio() routine completes */ 31362306a36Sopenharmony_ci folio_unlock(folio); 31462306a36Sopenharmony_ci return ret; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic int orangefs_write_begin(struct file *file, 31862306a36Sopenharmony_ci struct address_space *mapping, loff_t pos, unsigned len, 31962306a36Sopenharmony_ci struct page **pagep, void **fsdata) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci struct orangefs_write_range *wr; 32262306a36Sopenharmony_ci struct folio *folio; 32362306a36Sopenharmony_ci struct page *page; 32462306a36Sopenharmony_ci pgoff_t index; 32562306a36Sopenharmony_ci int ret; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci index = pos >> PAGE_SHIFT; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci page = grab_cache_page_write_begin(mapping, index); 33062306a36Sopenharmony_ci if (!page) 33162306a36Sopenharmony_ci return -ENOMEM; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci *pagep = page; 33462306a36Sopenharmony_ci folio = page_folio(page); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (folio_test_dirty(folio) && !folio_test_private(folio)) { 33762306a36Sopenharmony_ci /* 33862306a36Sopenharmony_ci * Should be impossible. If it happens, launder the page 33962306a36Sopenharmony_ci * since we don't know what's dirty. This will WARN in 34062306a36Sopenharmony_ci * orangefs_writepage_locked. 34162306a36Sopenharmony_ci */ 34262306a36Sopenharmony_ci ret = orangefs_launder_folio(folio); 34362306a36Sopenharmony_ci if (ret) 34462306a36Sopenharmony_ci return ret; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci if (folio_test_private(folio)) { 34762306a36Sopenharmony_ci struct orangefs_write_range *wr; 34862306a36Sopenharmony_ci wr = folio_get_private(folio); 34962306a36Sopenharmony_ci if (wr->pos + wr->len == pos && 35062306a36Sopenharmony_ci uid_eq(wr->uid, current_fsuid()) && 35162306a36Sopenharmony_ci gid_eq(wr->gid, current_fsgid())) { 35262306a36Sopenharmony_ci wr->len += len; 35362306a36Sopenharmony_ci goto okay; 35462306a36Sopenharmony_ci } else { 35562306a36Sopenharmony_ci ret = orangefs_launder_folio(folio); 35662306a36Sopenharmony_ci if (ret) 35762306a36Sopenharmony_ci return ret; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci wr = kmalloc(sizeof *wr, GFP_KERNEL); 36262306a36Sopenharmony_ci if (!wr) 36362306a36Sopenharmony_ci return -ENOMEM; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci wr->pos = pos; 36662306a36Sopenharmony_ci wr->len = len; 36762306a36Sopenharmony_ci wr->uid = current_fsuid(); 36862306a36Sopenharmony_ci wr->gid = current_fsgid(); 36962306a36Sopenharmony_ci folio_attach_private(folio, wr); 37062306a36Sopenharmony_ciokay: 37162306a36Sopenharmony_ci return 0; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic int orangefs_write_end(struct file *file, struct address_space *mapping, 37562306a36Sopenharmony_ci loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci struct inode *inode = page->mapping->host; 37862306a36Sopenharmony_ci loff_t last_pos = pos + copied; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* 38162306a36Sopenharmony_ci * No need to use i_size_read() here, the i_size 38262306a36Sopenharmony_ci * cannot change under us because we hold the i_mutex. 38362306a36Sopenharmony_ci */ 38462306a36Sopenharmony_ci if (last_pos > inode->i_size) 38562306a36Sopenharmony_ci i_size_write(inode, last_pos); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* zero the stale part of the page if we did a short copy */ 38862306a36Sopenharmony_ci if (!PageUptodate(page)) { 38962306a36Sopenharmony_ci unsigned from = pos & (PAGE_SIZE - 1); 39062306a36Sopenharmony_ci if (copied < len) { 39162306a36Sopenharmony_ci zero_user(page, from + copied, len - copied); 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci /* Set fully written pages uptodate. */ 39462306a36Sopenharmony_ci if (pos == page_offset(page) && 39562306a36Sopenharmony_ci (len == PAGE_SIZE || pos + len == inode->i_size)) { 39662306a36Sopenharmony_ci zero_user_segment(page, from + copied, PAGE_SIZE); 39762306a36Sopenharmony_ci SetPageUptodate(page); 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci set_page_dirty(page); 40262306a36Sopenharmony_ci unlock_page(page); 40362306a36Sopenharmony_ci put_page(page); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci mark_inode_dirty_sync(file_inode(file)); 40662306a36Sopenharmony_ci return copied; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic void orangefs_invalidate_folio(struct folio *folio, 41062306a36Sopenharmony_ci size_t offset, size_t length) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci struct orangefs_write_range *wr = folio_get_private(folio); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (offset == 0 && length == PAGE_SIZE) { 41562306a36Sopenharmony_ci kfree(folio_detach_private(folio)); 41662306a36Sopenharmony_ci return; 41762306a36Sopenharmony_ci /* write range entirely within invalidate range (or equal) */ 41862306a36Sopenharmony_ci } else if (folio_pos(folio) + offset <= wr->pos && 41962306a36Sopenharmony_ci wr->pos + wr->len <= folio_pos(folio) + offset + length) { 42062306a36Sopenharmony_ci kfree(folio_detach_private(folio)); 42162306a36Sopenharmony_ci /* XXX is this right? only caller in fs */ 42262306a36Sopenharmony_ci folio_cancel_dirty(folio); 42362306a36Sopenharmony_ci return; 42462306a36Sopenharmony_ci /* invalidate range chops off end of write range */ 42562306a36Sopenharmony_ci } else if (wr->pos < folio_pos(folio) + offset && 42662306a36Sopenharmony_ci wr->pos + wr->len <= folio_pos(folio) + offset + length && 42762306a36Sopenharmony_ci folio_pos(folio) + offset < wr->pos + wr->len) { 42862306a36Sopenharmony_ci size_t x; 42962306a36Sopenharmony_ci x = wr->pos + wr->len - (folio_pos(folio) + offset); 43062306a36Sopenharmony_ci WARN_ON(x > wr->len); 43162306a36Sopenharmony_ci wr->len -= x; 43262306a36Sopenharmony_ci wr->uid = current_fsuid(); 43362306a36Sopenharmony_ci wr->gid = current_fsgid(); 43462306a36Sopenharmony_ci /* invalidate range chops off beginning of write range */ 43562306a36Sopenharmony_ci } else if (folio_pos(folio) + offset <= wr->pos && 43662306a36Sopenharmony_ci folio_pos(folio) + offset + length < wr->pos + wr->len && 43762306a36Sopenharmony_ci wr->pos < folio_pos(folio) + offset + length) { 43862306a36Sopenharmony_ci size_t x; 43962306a36Sopenharmony_ci x = folio_pos(folio) + offset + length - wr->pos; 44062306a36Sopenharmony_ci WARN_ON(x > wr->len); 44162306a36Sopenharmony_ci wr->pos += x; 44262306a36Sopenharmony_ci wr->len -= x; 44362306a36Sopenharmony_ci wr->uid = current_fsuid(); 44462306a36Sopenharmony_ci wr->gid = current_fsgid(); 44562306a36Sopenharmony_ci /* invalidate range entirely within write range (punch hole) */ 44662306a36Sopenharmony_ci } else if (wr->pos < folio_pos(folio) + offset && 44762306a36Sopenharmony_ci folio_pos(folio) + offset + length < wr->pos + wr->len) { 44862306a36Sopenharmony_ci /* XXX what do we do here... should not WARN_ON */ 44962306a36Sopenharmony_ci WARN_ON(1); 45062306a36Sopenharmony_ci /* punch hole */ 45162306a36Sopenharmony_ci /* 45262306a36Sopenharmony_ci * should we just ignore this and write it out anyway? 45362306a36Sopenharmony_ci * it hardly makes sense 45462306a36Sopenharmony_ci */ 45562306a36Sopenharmony_ci return; 45662306a36Sopenharmony_ci /* non-overlapping ranges */ 45762306a36Sopenharmony_ci } else { 45862306a36Sopenharmony_ci /* WARN if they do overlap */ 45962306a36Sopenharmony_ci if (!((folio_pos(folio) + offset + length <= wr->pos) ^ 46062306a36Sopenharmony_ci (wr->pos + wr->len <= folio_pos(folio) + offset))) { 46162306a36Sopenharmony_ci WARN_ON(1); 46262306a36Sopenharmony_ci printk("invalidate range offset %llu length %zu\n", 46362306a36Sopenharmony_ci folio_pos(folio) + offset, length); 46462306a36Sopenharmony_ci printk("write range offset %llu length %zu\n", 46562306a36Sopenharmony_ci wr->pos, wr->len); 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci return; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* 47162306a36Sopenharmony_ci * Above there are returns where wr is freed or where we WARN. 47262306a36Sopenharmony_ci * Thus the following runs if wr was modified above. 47362306a36Sopenharmony_ci */ 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci orangefs_launder_folio(folio); 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_cistatic bool orangefs_release_folio(struct folio *folio, gfp_t foo) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci return !folio_test_private(folio); 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic void orangefs_free_folio(struct folio *folio) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci kfree(folio_detach_private(folio)); 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic int orangefs_launder_folio(struct folio *folio) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci int r = 0; 49162306a36Sopenharmony_ci struct writeback_control wbc = { 49262306a36Sopenharmony_ci .sync_mode = WB_SYNC_ALL, 49362306a36Sopenharmony_ci .nr_to_write = 0, 49462306a36Sopenharmony_ci }; 49562306a36Sopenharmony_ci folio_wait_writeback(folio); 49662306a36Sopenharmony_ci if (folio_clear_dirty_for_io(folio)) { 49762306a36Sopenharmony_ci r = orangefs_writepage_locked(&folio->page, &wbc); 49862306a36Sopenharmony_ci folio_end_writeback(folio); 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci return r; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic ssize_t orangefs_direct_IO(struct kiocb *iocb, 50462306a36Sopenharmony_ci struct iov_iter *iter) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci /* 50762306a36Sopenharmony_ci * Comment from original do_readv_writev: 50862306a36Sopenharmony_ci * Common entry point for read/write/readv/writev 50962306a36Sopenharmony_ci * This function will dispatch it to either the direct I/O 51062306a36Sopenharmony_ci * or buffered I/O path depending on the mount options and/or 51162306a36Sopenharmony_ci * augmented/extended metadata attached to the file. 51262306a36Sopenharmony_ci * Note: File extended attributes override any mount options. 51362306a36Sopenharmony_ci */ 51462306a36Sopenharmony_ci struct file *file = iocb->ki_filp; 51562306a36Sopenharmony_ci loff_t pos = iocb->ki_pos; 51662306a36Sopenharmony_ci enum ORANGEFS_io_type type = iov_iter_rw(iter) == WRITE ? 51762306a36Sopenharmony_ci ORANGEFS_IO_WRITE : ORANGEFS_IO_READ; 51862306a36Sopenharmony_ci loff_t *offset = &pos; 51962306a36Sopenharmony_ci struct inode *inode = file->f_mapping->host; 52062306a36Sopenharmony_ci struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 52162306a36Sopenharmony_ci struct orangefs_khandle *handle = &orangefs_inode->refn.khandle; 52262306a36Sopenharmony_ci size_t count = iov_iter_count(iter); 52362306a36Sopenharmony_ci ssize_t total_count = 0; 52462306a36Sopenharmony_ci ssize_t ret = -EINVAL; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci gossip_debug(GOSSIP_FILE_DEBUG, 52762306a36Sopenharmony_ci "%s-BEGIN(%pU): count(%d) after estimate_max_iovecs.\n", 52862306a36Sopenharmony_ci __func__, 52962306a36Sopenharmony_ci handle, 53062306a36Sopenharmony_ci (int)count); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci if (type == ORANGEFS_IO_WRITE) { 53362306a36Sopenharmony_ci gossip_debug(GOSSIP_FILE_DEBUG, 53462306a36Sopenharmony_ci "%s(%pU): proceeding with offset : %llu, " 53562306a36Sopenharmony_ci "size %d\n", 53662306a36Sopenharmony_ci __func__, 53762306a36Sopenharmony_ci handle, 53862306a36Sopenharmony_ci llu(*offset), 53962306a36Sopenharmony_ci (int)count); 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (count == 0) { 54362306a36Sopenharmony_ci ret = 0; 54462306a36Sopenharmony_ci goto out; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci while (iov_iter_count(iter)) { 54862306a36Sopenharmony_ci size_t each_count = iov_iter_count(iter); 54962306a36Sopenharmony_ci size_t amt_complete; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* how much to transfer in this loop iteration */ 55262306a36Sopenharmony_ci if (each_count > orangefs_bufmap_size_query()) 55362306a36Sopenharmony_ci each_count = orangefs_bufmap_size_query(); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci gossip_debug(GOSSIP_FILE_DEBUG, 55662306a36Sopenharmony_ci "%s(%pU): size of each_count(%d)\n", 55762306a36Sopenharmony_ci __func__, 55862306a36Sopenharmony_ci handle, 55962306a36Sopenharmony_ci (int)each_count); 56062306a36Sopenharmony_ci gossip_debug(GOSSIP_FILE_DEBUG, 56162306a36Sopenharmony_ci "%s(%pU): BEFORE wait_for_io: offset is %d\n", 56262306a36Sopenharmony_ci __func__, 56362306a36Sopenharmony_ci handle, 56462306a36Sopenharmony_ci (int)*offset); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci ret = wait_for_direct_io(type, inode, offset, iter, 56762306a36Sopenharmony_ci each_count, 0, NULL, NULL, file); 56862306a36Sopenharmony_ci gossip_debug(GOSSIP_FILE_DEBUG, 56962306a36Sopenharmony_ci "%s(%pU): return from wait_for_io:%d\n", 57062306a36Sopenharmony_ci __func__, 57162306a36Sopenharmony_ci handle, 57262306a36Sopenharmony_ci (int)ret); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (ret < 0) 57562306a36Sopenharmony_ci goto out; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci *offset += ret; 57862306a36Sopenharmony_ci total_count += ret; 57962306a36Sopenharmony_ci amt_complete = ret; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci gossip_debug(GOSSIP_FILE_DEBUG, 58262306a36Sopenharmony_ci "%s(%pU): AFTER wait_for_io: offset is %d\n", 58362306a36Sopenharmony_ci __func__, 58462306a36Sopenharmony_ci handle, 58562306a36Sopenharmony_ci (int)*offset); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* 58862306a36Sopenharmony_ci * if we got a short I/O operations, 58962306a36Sopenharmony_ci * fall out and return what we got so far 59062306a36Sopenharmony_ci */ 59162306a36Sopenharmony_ci if (amt_complete < each_count) 59262306a36Sopenharmony_ci break; 59362306a36Sopenharmony_ci } /*end while */ 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ciout: 59662306a36Sopenharmony_ci if (total_count > 0) 59762306a36Sopenharmony_ci ret = total_count; 59862306a36Sopenharmony_ci if (ret > 0) { 59962306a36Sopenharmony_ci if (type == ORANGEFS_IO_READ) { 60062306a36Sopenharmony_ci file_accessed(file); 60162306a36Sopenharmony_ci } else { 60262306a36Sopenharmony_ci file_update_time(file); 60362306a36Sopenharmony_ci if (*offset > i_size_read(inode)) 60462306a36Sopenharmony_ci i_size_write(inode, *offset); 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci gossip_debug(GOSSIP_FILE_DEBUG, 60962306a36Sopenharmony_ci "%s(%pU): Value(%d) returned.\n", 61062306a36Sopenharmony_ci __func__, 61162306a36Sopenharmony_ci handle, 61262306a36Sopenharmony_ci (int)ret); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci return ret; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci/** ORANGEFS2 implementation of address space operations */ 61862306a36Sopenharmony_cistatic const struct address_space_operations orangefs_address_operations = { 61962306a36Sopenharmony_ci .writepage = orangefs_writepage, 62062306a36Sopenharmony_ci .readahead = orangefs_readahead, 62162306a36Sopenharmony_ci .read_folio = orangefs_read_folio, 62262306a36Sopenharmony_ci .writepages = orangefs_writepages, 62362306a36Sopenharmony_ci .dirty_folio = filemap_dirty_folio, 62462306a36Sopenharmony_ci .write_begin = orangefs_write_begin, 62562306a36Sopenharmony_ci .write_end = orangefs_write_end, 62662306a36Sopenharmony_ci .invalidate_folio = orangefs_invalidate_folio, 62762306a36Sopenharmony_ci .release_folio = orangefs_release_folio, 62862306a36Sopenharmony_ci .free_folio = orangefs_free_folio, 62962306a36Sopenharmony_ci .launder_folio = orangefs_launder_folio, 63062306a36Sopenharmony_ci .direct_IO = orangefs_direct_IO, 63162306a36Sopenharmony_ci}; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_civm_fault_t orangefs_page_mkwrite(struct vm_fault *vmf) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci struct folio *folio = page_folio(vmf->page); 63662306a36Sopenharmony_ci struct inode *inode = file_inode(vmf->vma->vm_file); 63762306a36Sopenharmony_ci struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 63862306a36Sopenharmony_ci unsigned long *bitlock = &orangefs_inode->bitlock; 63962306a36Sopenharmony_ci vm_fault_t ret; 64062306a36Sopenharmony_ci struct orangefs_write_range *wr; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci sb_start_pagefault(inode->i_sb); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if (wait_on_bit(bitlock, 1, TASK_KILLABLE)) { 64562306a36Sopenharmony_ci ret = VM_FAULT_RETRY; 64662306a36Sopenharmony_ci goto out; 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci folio_lock(folio); 65062306a36Sopenharmony_ci if (folio_test_dirty(folio) && !folio_test_private(folio)) { 65162306a36Sopenharmony_ci /* 65262306a36Sopenharmony_ci * Should be impossible. If it happens, launder the folio 65362306a36Sopenharmony_ci * since we don't know what's dirty. This will WARN in 65462306a36Sopenharmony_ci * orangefs_writepage_locked. 65562306a36Sopenharmony_ci */ 65662306a36Sopenharmony_ci if (orangefs_launder_folio(folio)) { 65762306a36Sopenharmony_ci ret = VM_FAULT_LOCKED|VM_FAULT_RETRY; 65862306a36Sopenharmony_ci goto out; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci if (folio_test_private(folio)) { 66262306a36Sopenharmony_ci wr = folio_get_private(folio); 66362306a36Sopenharmony_ci if (uid_eq(wr->uid, current_fsuid()) && 66462306a36Sopenharmony_ci gid_eq(wr->gid, current_fsgid())) { 66562306a36Sopenharmony_ci wr->pos = page_offset(vmf->page); 66662306a36Sopenharmony_ci wr->len = PAGE_SIZE; 66762306a36Sopenharmony_ci goto okay; 66862306a36Sopenharmony_ci } else { 66962306a36Sopenharmony_ci if (orangefs_launder_folio(folio)) { 67062306a36Sopenharmony_ci ret = VM_FAULT_LOCKED|VM_FAULT_RETRY; 67162306a36Sopenharmony_ci goto out; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci wr = kmalloc(sizeof *wr, GFP_KERNEL); 67662306a36Sopenharmony_ci if (!wr) { 67762306a36Sopenharmony_ci ret = VM_FAULT_LOCKED|VM_FAULT_RETRY; 67862306a36Sopenharmony_ci goto out; 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci wr->pos = page_offset(vmf->page); 68162306a36Sopenharmony_ci wr->len = PAGE_SIZE; 68262306a36Sopenharmony_ci wr->uid = current_fsuid(); 68362306a36Sopenharmony_ci wr->gid = current_fsgid(); 68462306a36Sopenharmony_ci folio_attach_private(folio, wr); 68562306a36Sopenharmony_ciokay: 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci file_update_time(vmf->vma->vm_file); 68862306a36Sopenharmony_ci if (folio->mapping != inode->i_mapping) { 68962306a36Sopenharmony_ci folio_unlock(folio); 69062306a36Sopenharmony_ci ret = VM_FAULT_LOCKED|VM_FAULT_NOPAGE; 69162306a36Sopenharmony_ci goto out; 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci /* 69562306a36Sopenharmony_ci * We mark the folio dirty already here so that when freeze is in 69662306a36Sopenharmony_ci * progress, we are guaranteed that writeback during freezing will 69762306a36Sopenharmony_ci * see the dirty folio and writeprotect it again. 69862306a36Sopenharmony_ci */ 69962306a36Sopenharmony_ci folio_mark_dirty(folio); 70062306a36Sopenharmony_ci folio_wait_stable(folio); 70162306a36Sopenharmony_ci ret = VM_FAULT_LOCKED; 70262306a36Sopenharmony_ciout: 70362306a36Sopenharmony_ci sb_end_pagefault(inode->i_sb); 70462306a36Sopenharmony_ci return ret; 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_cistatic int orangefs_setattr_size(struct inode *inode, struct iattr *iattr) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 71062306a36Sopenharmony_ci struct orangefs_kernel_op_s *new_op; 71162306a36Sopenharmony_ci loff_t orig_size; 71262306a36Sopenharmony_ci int ret = -EINVAL; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci gossip_debug(GOSSIP_INODE_DEBUG, 71562306a36Sopenharmony_ci "%s: %pU: Handle is %pU | fs_id %d | size is %llu\n", 71662306a36Sopenharmony_ci __func__, 71762306a36Sopenharmony_ci get_khandle_from_ino(inode), 71862306a36Sopenharmony_ci &orangefs_inode->refn.khandle, 71962306a36Sopenharmony_ci orangefs_inode->refn.fs_id, 72062306a36Sopenharmony_ci iattr->ia_size); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci /* Ensure that we have a up to date size, so we know if it changed. */ 72362306a36Sopenharmony_ci ret = orangefs_inode_getattr(inode, ORANGEFS_GETATTR_SIZE); 72462306a36Sopenharmony_ci if (ret == -ESTALE) 72562306a36Sopenharmony_ci ret = -EIO; 72662306a36Sopenharmony_ci if (ret) { 72762306a36Sopenharmony_ci gossip_err("%s: orangefs_inode_getattr failed, ret:%d:.\n", 72862306a36Sopenharmony_ci __func__, ret); 72962306a36Sopenharmony_ci return ret; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci orig_size = i_size_read(inode); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci /* This is truncate_setsize in a different order. */ 73462306a36Sopenharmony_ci truncate_pagecache(inode, iattr->ia_size); 73562306a36Sopenharmony_ci i_size_write(inode, iattr->ia_size); 73662306a36Sopenharmony_ci if (iattr->ia_size > orig_size) 73762306a36Sopenharmony_ci pagecache_isize_extended(inode, orig_size, iattr->ia_size); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci new_op = op_alloc(ORANGEFS_VFS_OP_TRUNCATE); 74062306a36Sopenharmony_ci if (!new_op) 74162306a36Sopenharmony_ci return -ENOMEM; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci new_op->upcall.req.truncate.refn = orangefs_inode->refn; 74462306a36Sopenharmony_ci new_op->upcall.req.truncate.size = (__s64) iattr->ia_size; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci ret = service_operation(new_op, 74762306a36Sopenharmony_ci __func__, 74862306a36Sopenharmony_ci get_interruptible_flag(inode)); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci /* 75162306a36Sopenharmony_ci * the truncate has no downcall members to retrieve, but 75262306a36Sopenharmony_ci * the status value tells us if it went through ok or not 75362306a36Sopenharmony_ci */ 75462306a36Sopenharmony_ci gossip_debug(GOSSIP_INODE_DEBUG, "%s: ret:%d:\n", __func__, ret); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci op_release(new_op); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (ret != 0) 75962306a36Sopenharmony_ci return ret; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (orig_size != i_size_read(inode)) 76262306a36Sopenharmony_ci iattr->ia_valid |= ATTR_CTIME | ATTR_MTIME; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci return ret; 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ciint __orangefs_setattr(struct inode *inode, struct iattr *iattr) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci int ret; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (iattr->ia_valid & ATTR_MODE) { 77262306a36Sopenharmony_ci if (iattr->ia_mode & (S_ISVTX)) { 77362306a36Sopenharmony_ci if (is_root_handle(inode)) { 77462306a36Sopenharmony_ci /* 77562306a36Sopenharmony_ci * allow sticky bit to be set on root (since 77662306a36Sopenharmony_ci * it shows up that way by default anyhow), 77762306a36Sopenharmony_ci * but don't show it to the server 77862306a36Sopenharmony_ci */ 77962306a36Sopenharmony_ci iattr->ia_mode -= S_ISVTX; 78062306a36Sopenharmony_ci } else { 78162306a36Sopenharmony_ci gossip_debug(GOSSIP_UTILS_DEBUG, 78262306a36Sopenharmony_ci "User attempted to set sticky bit on non-root directory; returning EINVAL.\n"); 78362306a36Sopenharmony_ci ret = -EINVAL; 78462306a36Sopenharmony_ci goto out; 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci if (iattr->ia_mode & (S_ISUID)) { 78862306a36Sopenharmony_ci gossip_debug(GOSSIP_UTILS_DEBUG, 78962306a36Sopenharmony_ci "Attempting to set setuid bit (not supported); returning EINVAL.\n"); 79062306a36Sopenharmony_ci ret = -EINVAL; 79162306a36Sopenharmony_ci goto out; 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (iattr->ia_valid & ATTR_SIZE) { 79662306a36Sopenharmony_ci ret = orangefs_setattr_size(inode, iattr); 79762306a36Sopenharmony_ci if (ret) 79862306a36Sopenharmony_ci goto out; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ciagain: 80262306a36Sopenharmony_ci spin_lock(&inode->i_lock); 80362306a36Sopenharmony_ci if (ORANGEFS_I(inode)->attr_valid) { 80462306a36Sopenharmony_ci if (uid_eq(ORANGEFS_I(inode)->attr_uid, current_fsuid()) && 80562306a36Sopenharmony_ci gid_eq(ORANGEFS_I(inode)->attr_gid, current_fsgid())) { 80662306a36Sopenharmony_ci ORANGEFS_I(inode)->attr_valid = iattr->ia_valid; 80762306a36Sopenharmony_ci } else { 80862306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 80962306a36Sopenharmony_ci write_inode_now(inode, 1); 81062306a36Sopenharmony_ci goto again; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci } else { 81362306a36Sopenharmony_ci ORANGEFS_I(inode)->attr_valid = iattr->ia_valid; 81462306a36Sopenharmony_ci ORANGEFS_I(inode)->attr_uid = current_fsuid(); 81562306a36Sopenharmony_ci ORANGEFS_I(inode)->attr_gid = current_fsgid(); 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci setattr_copy(&nop_mnt_idmap, inode, iattr); 81862306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 81962306a36Sopenharmony_ci mark_inode_dirty(inode); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci ret = 0; 82262306a36Sopenharmony_ciout: 82362306a36Sopenharmony_ci return ret; 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ciint __orangefs_setattr_mode(struct dentry *dentry, struct iattr *iattr) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci int ret; 82962306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci ret = __orangefs_setattr(inode, iattr); 83262306a36Sopenharmony_ci /* change mode on a file that has ACLs */ 83362306a36Sopenharmony_ci if (!ret && (iattr->ia_valid & ATTR_MODE)) 83462306a36Sopenharmony_ci ret = posix_acl_chmod(&nop_mnt_idmap, dentry, inode->i_mode); 83562306a36Sopenharmony_ci return ret; 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci/* 83962306a36Sopenharmony_ci * Change attributes of an object referenced by dentry. 84062306a36Sopenharmony_ci */ 84162306a36Sopenharmony_ciint orangefs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, 84262306a36Sopenharmony_ci struct iattr *iattr) 84362306a36Sopenharmony_ci{ 84462306a36Sopenharmony_ci int ret; 84562306a36Sopenharmony_ci gossip_debug(GOSSIP_INODE_DEBUG, "__orangefs_setattr: called on %pd\n", 84662306a36Sopenharmony_ci dentry); 84762306a36Sopenharmony_ci ret = setattr_prepare(&nop_mnt_idmap, dentry, iattr); 84862306a36Sopenharmony_ci if (ret) 84962306a36Sopenharmony_ci goto out; 85062306a36Sopenharmony_ci ret = __orangefs_setattr_mode(dentry, iattr); 85162306a36Sopenharmony_ci sync_inode_metadata(d_inode(dentry), 1); 85262306a36Sopenharmony_ciout: 85362306a36Sopenharmony_ci gossip_debug(GOSSIP_INODE_DEBUG, "orangefs_setattr: returning %d\n", 85462306a36Sopenharmony_ci ret); 85562306a36Sopenharmony_ci return ret; 85662306a36Sopenharmony_ci} 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci/* 85962306a36Sopenharmony_ci * Obtain attributes of an object given a dentry 86062306a36Sopenharmony_ci */ 86162306a36Sopenharmony_ciint orangefs_getattr(struct mnt_idmap *idmap, const struct path *path, 86262306a36Sopenharmony_ci struct kstat *stat, u32 request_mask, unsigned int flags) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci int ret; 86562306a36Sopenharmony_ci struct inode *inode = path->dentry->d_inode; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci gossip_debug(GOSSIP_INODE_DEBUG, 86862306a36Sopenharmony_ci "orangefs_getattr: called on %pd mask %u\n", 86962306a36Sopenharmony_ci path->dentry, request_mask); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci ret = orangefs_inode_getattr(inode, 87262306a36Sopenharmony_ci request_mask & STATX_SIZE ? ORANGEFS_GETATTR_SIZE : 0); 87362306a36Sopenharmony_ci if (ret == 0) { 87462306a36Sopenharmony_ci generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci /* override block size reported to stat */ 87762306a36Sopenharmony_ci if (!(request_mask & STATX_SIZE)) 87862306a36Sopenharmony_ci stat->result_mask &= ~STATX_SIZE; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci generic_fill_statx_attr(inode, stat); 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci return ret; 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ciint orangefs_permission(struct mnt_idmap *idmap, 88662306a36Sopenharmony_ci struct inode *inode, int mask) 88762306a36Sopenharmony_ci{ 88862306a36Sopenharmony_ci int ret; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci if (mask & MAY_NOT_BLOCK) 89162306a36Sopenharmony_ci return -ECHILD; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci gossip_debug(GOSSIP_INODE_DEBUG, "%s: refreshing\n", __func__); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci /* Make sure the permission (and other common attrs) are up to date. */ 89662306a36Sopenharmony_ci ret = orangefs_inode_getattr(inode, 0); 89762306a36Sopenharmony_ci if (ret < 0) 89862306a36Sopenharmony_ci return ret; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci return generic_permission(&nop_mnt_idmap, inode, mask); 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ciint orangefs_update_time(struct inode *inode, int flags) 90462306a36Sopenharmony_ci{ 90562306a36Sopenharmony_ci struct iattr iattr; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci gossip_debug(GOSSIP_INODE_DEBUG, "orangefs_update_time: %pU\n", 90862306a36Sopenharmony_ci get_khandle_from_ino(inode)); 90962306a36Sopenharmony_ci flags = generic_update_time(inode, flags); 91062306a36Sopenharmony_ci memset(&iattr, 0, sizeof iattr); 91162306a36Sopenharmony_ci if (flags & S_ATIME) 91262306a36Sopenharmony_ci iattr.ia_valid |= ATTR_ATIME; 91362306a36Sopenharmony_ci if (flags & S_CTIME) 91462306a36Sopenharmony_ci iattr.ia_valid |= ATTR_CTIME; 91562306a36Sopenharmony_ci if (flags & S_MTIME) 91662306a36Sopenharmony_ci iattr.ia_valid |= ATTR_MTIME; 91762306a36Sopenharmony_ci return __orangefs_setattr(inode, &iattr); 91862306a36Sopenharmony_ci} 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_cistatic int orangefs_fileattr_get(struct dentry *dentry, struct fileattr *fa) 92162306a36Sopenharmony_ci{ 92262306a36Sopenharmony_ci u64 val = 0; 92362306a36Sopenharmony_ci int ret; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci gossip_debug(GOSSIP_FILE_DEBUG, "%s: called on %pd\n", __func__, 92662306a36Sopenharmony_ci dentry); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci ret = orangefs_inode_getxattr(d_inode(dentry), 92962306a36Sopenharmony_ci "user.pvfs2.meta_hint", 93062306a36Sopenharmony_ci &val, sizeof(val)); 93162306a36Sopenharmony_ci if (ret < 0 && ret != -ENODATA) 93262306a36Sopenharmony_ci return ret; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci gossip_debug(GOSSIP_FILE_DEBUG, "%s: flags=%u\n", __func__, (u32) val); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci fileattr_fill_flags(fa, val); 93762306a36Sopenharmony_ci return 0; 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic int orangefs_fileattr_set(struct mnt_idmap *idmap, 94162306a36Sopenharmony_ci struct dentry *dentry, struct fileattr *fa) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci u64 val = 0; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci gossip_debug(GOSSIP_FILE_DEBUG, "%s: called on %pd\n", __func__, 94662306a36Sopenharmony_ci dentry); 94762306a36Sopenharmony_ci /* 94862306a36Sopenharmony_ci * ORANGEFS_MIRROR_FL is set internally when the mirroring mode is 94962306a36Sopenharmony_ci * turned on for a file. The user is not allowed to turn on this bit, 95062306a36Sopenharmony_ci * but the bit is present if the user first gets the flags and then 95162306a36Sopenharmony_ci * updates the flags with some new settings. So, we ignore it in the 95262306a36Sopenharmony_ci * following edit. bligon. 95362306a36Sopenharmony_ci */ 95462306a36Sopenharmony_ci if (fileattr_has_fsx(fa) || 95562306a36Sopenharmony_ci (fa->flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NOATIME_FL | ORANGEFS_MIRROR_FL))) { 95662306a36Sopenharmony_ci gossip_err("%s: only supports setting one of FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NOATIME_FL\n", 95762306a36Sopenharmony_ci __func__); 95862306a36Sopenharmony_ci return -EOPNOTSUPP; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci val = fa->flags; 96162306a36Sopenharmony_ci gossip_debug(GOSSIP_FILE_DEBUG, "%s: flags=%u\n", __func__, (u32) val); 96262306a36Sopenharmony_ci return orangefs_inode_setxattr(d_inode(dentry), 96362306a36Sopenharmony_ci "user.pvfs2.meta_hint", 96462306a36Sopenharmony_ci &val, sizeof(val), 0); 96562306a36Sopenharmony_ci} 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci/* ORANGEFS2 implementation of VFS inode operations for files */ 96862306a36Sopenharmony_cistatic const struct inode_operations orangefs_file_inode_operations = { 96962306a36Sopenharmony_ci .get_inode_acl = orangefs_get_acl, 97062306a36Sopenharmony_ci .set_acl = orangefs_set_acl, 97162306a36Sopenharmony_ci .setattr = orangefs_setattr, 97262306a36Sopenharmony_ci .getattr = orangefs_getattr, 97362306a36Sopenharmony_ci .listxattr = orangefs_listxattr, 97462306a36Sopenharmony_ci .permission = orangefs_permission, 97562306a36Sopenharmony_ci .update_time = orangefs_update_time, 97662306a36Sopenharmony_ci .fileattr_get = orangefs_fileattr_get, 97762306a36Sopenharmony_ci .fileattr_set = orangefs_fileattr_set, 97862306a36Sopenharmony_ci}; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_cistatic int orangefs_init_iops(struct inode *inode) 98162306a36Sopenharmony_ci{ 98262306a36Sopenharmony_ci inode->i_mapping->a_ops = &orangefs_address_operations; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci switch (inode->i_mode & S_IFMT) { 98562306a36Sopenharmony_ci case S_IFREG: 98662306a36Sopenharmony_ci inode->i_op = &orangefs_file_inode_operations; 98762306a36Sopenharmony_ci inode->i_fop = &orangefs_file_operations; 98862306a36Sopenharmony_ci break; 98962306a36Sopenharmony_ci case S_IFLNK: 99062306a36Sopenharmony_ci inode->i_op = &orangefs_symlink_inode_operations; 99162306a36Sopenharmony_ci break; 99262306a36Sopenharmony_ci case S_IFDIR: 99362306a36Sopenharmony_ci inode->i_op = &orangefs_dir_inode_operations; 99462306a36Sopenharmony_ci inode->i_fop = &orangefs_dir_operations; 99562306a36Sopenharmony_ci break; 99662306a36Sopenharmony_ci default: 99762306a36Sopenharmony_ci gossip_debug(GOSSIP_INODE_DEBUG, 99862306a36Sopenharmony_ci "%s: unsupported mode\n", 99962306a36Sopenharmony_ci __func__); 100062306a36Sopenharmony_ci return -EINVAL; 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci return 0; 100462306a36Sopenharmony_ci} 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci/* 100762306a36Sopenharmony_ci * Given an ORANGEFS object identifier (fsid, handle), convert it into 100862306a36Sopenharmony_ci * a ino_t type that will be used as a hash-index from where the handle will 100962306a36Sopenharmony_ci * be searched for in the VFS hash table of inodes. 101062306a36Sopenharmony_ci */ 101162306a36Sopenharmony_cistatic inline ino_t orangefs_handle_hash(struct orangefs_object_kref *ref) 101262306a36Sopenharmony_ci{ 101362306a36Sopenharmony_ci if (!ref) 101462306a36Sopenharmony_ci return 0; 101562306a36Sopenharmony_ci return orangefs_khandle_to_ino(&(ref->khandle)); 101662306a36Sopenharmony_ci} 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci/* 101962306a36Sopenharmony_ci * Called to set up an inode from iget5_locked. 102062306a36Sopenharmony_ci */ 102162306a36Sopenharmony_cistatic int orangefs_set_inode(struct inode *inode, void *data) 102262306a36Sopenharmony_ci{ 102362306a36Sopenharmony_ci struct orangefs_object_kref *ref = (struct orangefs_object_kref *) data; 102462306a36Sopenharmony_ci ORANGEFS_I(inode)->refn.fs_id = ref->fs_id; 102562306a36Sopenharmony_ci ORANGEFS_I(inode)->refn.khandle = ref->khandle; 102662306a36Sopenharmony_ci ORANGEFS_I(inode)->attr_valid = 0; 102762306a36Sopenharmony_ci hash_init(ORANGEFS_I(inode)->xattr_cache); 102862306a36Sopenharmony_ci ORANGEFS_I(inode)->mapping_time = jiffies - 1; 102962306a36Sopenharmony_ci ORANGEFS_I(inode)->bitlock = 0; 103062306a36Sopenharmony_ci return 0; 103162306a36Sopenharmony_ci} 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci/* 103462306a36Sopenharmony_ci * Called to determine if handles match. 103562306a36Sopenharmony_ci */ 103662306a36Sopenharmony_cistatic int orangefs_test_inode(struct inode *inode, void *data) 103762306a36Sopenharmony_ci{ 103862306a36Sopenharmony_ci struct orangefs_object_kref *ref = (struct orangefs_object_kref *) data; 103962306a36Sopenharmony_ci struct orangefs_inode_s *orangefs_inode = NULL; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci orangefs_inode = ORANGEFS_I(inode); 104262306a36Sopenharmony_ci /* test handles and fs_ids... */ 104362306a36Sopenharmony_ci return (!ORANGEFS_khandle_cmp(&(orangefs_inode->refn.khandle), 104462306a36Sopenharmony_ci &(ref->khandle)) && 104562306a36Sopenharmony_ci orangefs_inode->refn.fs_id == ref->fs_id); 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci/* 104962306a36Sopenharmony_ci * Front-end to lookup the inode-cache maintained by the VFS using the ORANGEFS 105062306a36Sopenharmony_ci * file handle. 105162306a36Sopenharmony_ci * 105262306a36Sopenharmony_ci * @sb: the file system super block instance. 105362306a36Sopenharmony_ci * @ref: The ORANGEFS object for which we are trying to locate an inode. 105462306a36Sopenharmony_ci */ 105562306a36Sopenharmony_cistruct inode *orangefs_iget(struct super_block *sb, 105662306a36Sopenharmony_ci struct orangefs_object_kref *ref) 105762306a36Sopenharmony_ci{ 105862306a36Sopenharmony_ci struct inode *inode = NULL; 105962306a36Sopenharmony_ci unsigned long hash; 106062306a36Sopenharmony_ci int error; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci hash = orangefs_handle_hash(ref); 106362306a36Sopenharmony_ci inode = iget5_locked(sb, 106462306a36Sopenharmony_ci hash, 106562306a36Sopenharmony_ci orangefs_test_inode, 106662306a36Sopenharmony_ci orangefs_set_inode, 106762306a36Sopenharmony_ci ref); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if (!inode) 107062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci if (!(inode->i_state & I_NEW)) 107362306a36Sopenharmony_ci return inode; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci error = orangefs_inode_getattr(inode, ORANGEFS_GETATTR_NEW); 107662306a36Sopenharmony_ci if (error) { 107762306a36Sopenharmony_ci iget_failed(inode); 107862306a36Sopenharmony_ci return ERR_PTR(error); 107962306a36Sopenharmony_ci } 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci inode->i_ino = hash; /* needed for stat etc */ 108262306a36Sopenharmony_ci orangefs_init_iops(inode); 108362306a36Sopenharmony_ci unlock_new_inode(inode); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci gossip_debug(GOSSIP_INODE_DEBUG, 108662306a36Sopenharmony_ci "iget handle %pU, fsid %d hash %ld i_ino %lu\n", 108762306a36Sopenharmony_ci &ref->khandle, 108862306a36Sopenharmony_ci ref->fs_id, 108962306a36Sopenharmony_ci hash, 109062306a36Sopenharmony_ci inode->i_ino); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci return inode; 109362306a36Sopenharmony_ci} 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci/* 109662306a36Sopenharmony_ci * Allocate an inode for a newly created file and insert it into the inode hash. 109762306a36Sopenharmony_ci */ 109862306a36Sopenharmony_cistruct inode *orangefs_new_inode(struct super_block *sb, struct inode *dir, 109962306a36Sopenharmony_ci umode_t mode, dev_t dev, struct orangefs_object_kref *ref) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci struct posix_acl *acl = NULL, *default_acl = NULL; 110262306a36Sopenharmony_ci unsigned long hash = orangefs_handle_hash(ref); 110362306a36Sopenharmony_ci struct inode *inode; 110462306a36Sopenharmony_ci int error; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci gossip_debug(GOSSIP_INODE_DEBUG, 110762306a36Sopenharmony_ci "%s:(sb is %p | MAJOR(dev)=%u | MINOR(dev)=%u mode=%o)\n", 110862306a36Sopenharmony_ci __func__, 110962306a36Sopenharmony_ci sb, 111062306a36Sopenharmony_ci MAJOR(dev), 111162306a36Sopenharmony_ci MINOR(dev), 111262306a36Sopenharmony_ci mode); 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci inode = new_inode(sb); 111562306a36Sopenharmony_ci if (!inode) 111662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci error = posix_acl_create(dir, &mode, &default_acl, &acl); 111962306a36Sopenharmony_ci if (error) 112062306a36Sopenharmony_ci goto out_iput; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci orangefs_set_inode(inode, ref); 112362306a36Sopenharmony_ci inode->i_ino = hash; /* needed for stat etc */ 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci error = orangefs_inode_getattr(inode, ORANGEFS_GETATTR_NEW); 112662306a36Sopenharmony_ci if (error) 112762306a36Sopenharmony_ci goto out_iput; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci orangefs_init_iops(inode); 113062306a36Sopenharmony_ci inode->i_rdev = dev; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci if (default_acl) { 113362306a36Sopenharmony_ci error = __orangefs_set_acl(inode, default_acl, 113462306a36Sopenharmony_ci ACL_TYPE_DEFAULT); 113562306a36Sopenharmony_ci if (error) 113662306a36Sopenharmony_ci goto out_iput; 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci if (acl) { 114062306a36Sopenharmony_ci error = __orangefs_set_acl(inode, acl, ACL_TYPE_ACCESS); 114162306a36Sopenharmony_ci if (error) 114262306a36Sopenharmony_ci goto out_iput; 114362306a36Sopenharmony_ci } 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci error = insert_inode_locked4(inode, hash, orangefs_test_inode, ref); 114662306a36Sopenharmony_ci if (error < 0) 114762306a36Sopenharmony_ci goto out_iput; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci gossip_debug(GOSSIP_INODE_DEBUG, 115062306a36Sopenharmony_ci "Initializing ACL's for inode %pU\n", 115162306a36Sopenharmony_ci get_khandle_from_ino(inode)); 115262306a36Sopenharmony_ci if (mode != inode->i_mode) { 115362306a36Sopenharmony_ci struct iattr iattr = { 115462306a36Sopenharmony_ci .ia_mode = mode, 115562306a36Sopenharmony_ci .ia_valid = ATTR_MODE, 115662306a36Sopenharmony_ci }; 115762306a36Sopenharmony_ci inode->i_mode = mode; 115862306a36Sopenharmony_ci __orangefs_setattr(inode, &iattr); 115962306a36Sopenharmony_ci __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci posix_acl_release(acl); 116262306a36Sopenharmony_ci posix_acl_release(default_acl); 116362306a36Sopenharmony_ci return inode; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ciout_iput: 116662306a36Sopenharmony_ci iput(inode); 116762306a36Sopenharmony_ci posix_acl_release(acl); 116862306a36Sopenharmony_ci posix_acl_release(default_acl); 116962306a36Sopenharmony_ci return ERR_PTR(error); 117062306a36Sopenharmony_ci} 1171