- RETURN(rc);
-}
-
-static void ll_set_file_contended(struct inode *inode)
-{
- struct ll_inode_info *lli = ll_i2info(inode);
- cfs_time_t now = cfs_time_current();
-
- spin_lock(&lli->lli_lock);
- lli->lli_contention_time = now;
- lli->lli_flags |= LLIF_CONTENDED;
- spin_unlock(&lli->lli_lock);
-}
-
-void ll_clear_file_contended(struct inode *inode)
-{
- struct ll_inode_info *lli = ll_i2info(inode);
-
- spin_lock(&lli->lli_lock);
- lli->lli_flags &= ~LLIF_CONTENDED;
- spin_unlock(&lli->lli_lock);
-}
-
-static int ll_is_file_contended(struct file *file)
-{
- struct inode *inode = file->f_dentry->d_inode;
- struct ll_inode_info *lli = ll_i2info(inode);
- struct ll_sb_info *sbi = ll_i2sbi(inode);
- struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
- ENTRY;
-
- if (!(sbi->ll_lco.lco_flags & OBD_CONNECT_SRVLOCK)) {
- CDEBUG(D_INFO, "the server does not support SRVLOCK feature,"
- " osc connect flags = 0x"LPX64"\n",
- sbi->ll_lco.lco_flags);
- RETURN(0);
- }
- if (fd && (fd->fd_flags & LL_FILE_IGNORE_LOCK))
- RETURN(1);
- if (lli->lli_flags & LLIF_CONTENDED) {
- cfs_time_t cur_time = cfs_time_current();
- cfs_time_t retry_time;
-
- retry_time = cfs_time_add(
- lli->lli_contention_time,
- cfs_time_seconds(sbi->ll_contention_time));
- if (cfs_time_after(cur_time, retry_time)) {
- ll_clear_file_contended(inode);
- RETURN(0);
- }
- RETURN(1);
- }
- RETURN(0);
-}
-
-static int ll_file_get_tree_lock(struct ll_lock_tree *tree, struct file *file,
- const char *buf, size_t count,
- loff_t start, loff_t end, int rw)
-{
- int append;
- int tree_locked = 0;
- int rc;
- struct inode * inode = file->f_dentry->d_inode;
- ENTRY;
-
- append = (rw == OBD_BRW_WRITE) && (file->f_flags & O_APPEND);
-
- if (append || !ll_is_file_contended(file)) {
- struct ll_lock_tree_node *node;
- int ast_flags;
-
- ast_flags = append ? 0 : LDLM_FL_DENY_ON_CONTENTION;
- if (file->f_flags & O_NONBLOCK)
- ast_flags |= LDLM_FL_BLOCK_NOWAIT;
- node = ll_node_from_inode(inode, start, end,
- (rw == OBD_BRW_WRITE) ? LCK_PW : LCK_PR);
- if (IS_ERR(node)) {
- rc = PTR_ERR(node);
- GOTO(out, rc);
- }
- tree->lt_fd = LUSTRE_FPRIVATE(file);
- rc = ll_tree_lock(tree, node, buf, count, ast_flags);
- if (rc == 0)
- tree_locked = 1;
- else if (rc == -EUSERS)
- ll_set_file_contended(inode);
- else
- GOTO(out, rc);
- }
- RETURN(tree_locked);
-out:
- return rc;
-}
-
-/**
- * Checks if requested extent lock is compatible with a lock under a page.
- *
- * Checks if the lock under \a page is compatible with a read or write lock
- * (specified by \a rw) for an extent [\a start , \a end].
- *
- * \param page the page under which lock is considered
- * \param rw OBD_BRW_READ if requested for reading,
- * OBD_BRW_WRITE if requested for writing
- * \param start start of the requested extent
- * \param end end of the requested extent
- * \param cookie transparent parameter for passing locking context
- *
- * \post result == 1, *cookie == context, appropriate lock is referenced or
- * \post result == 0
- *
- * \retval 1 owned lock is reused for the request
- * \retval 0 no lock reused for the request
- *
- * \see ll_release_short_lock
- */
-static int ll_reget_short_lock(struct page *page, int rw,
- obd_off start, obd_off end,
- void **cookie)
-{
- struct ll_async_page *llap;
- struct obd_export *exp;
- struct inode *inode = page->mapping->host;
-
- ENTRY;
-
- exp = ll_i2dtexp(inode);
- if (exp == NULL)
- RETURN(0);
-
- llap = llap_cast_private(page);
- if (llap == NULL)
- RETURN(0);
-
- RETURN(obd_reget_short_lock(exp, ll_i2info(inode)->lli_smd,
- &llap->llap_cookie, rw, start, end,
- cookie));
-}
-
-/**
- * Releases a reference to a lock taken in a "fast" way.
- *
- * Releases a read or a write (specified by \a rw) lock
- * referenced by \a cookie.
- *
- * \param inode inode to which data belong
- * \param end end of the locked extent
- * \param rw OBD_BRW_READ if requested for reading,
- * OBD_BRW_WRITE if requested for writing
- * \param cookie transparent parameter for passing locking context
- *
- * \post appropriate lock is dereferenced
- *
- * \see ll_reget_short_lock
- */
-static void ll_release_short_lock(struct inode *inode, obd_off end,
- void *cookie, int rw)
-{
- struct obd_export *exp;
- int rc;
-
- exp = ll_i2dtexp(inode);
- if (exp == NULL)
- return;
-
- rc = obd_release_short_lock(exp, ll_i2info(inode)->lli_smd, end,
- cookie, rw);
- if (rc < 0)
- CERROR("unlock failed (%d)\n", rc);
-}
-
-/**
- * Checks if requested extent lock is compatible
- * with a lock under a page in page cache.
- *
- * Checks if a lock under some \a page is compatible with a read or write lock
- * (specified by \a rw) for an extent [\a start , \a end].
- *
- * \param file the file under which lock is considered
- * \param rw OBD_BRW_READ if requested for reading,
- * OBD_BRW_WRITE if requested for writing
- * \param ppos start of the requested extent
- * \param end end of the requested extent
- * \param cookie transparent parameter for passing locking context
- * \param buf userspace buffer for the data
- *
- * \post result == 1, *cookie == context, appropriate lock is referenced
- * \post retuls == 0
- *
- * \retval 1 owned lock is reused for the request
- * \retval 0 no lock reused for the request
- *
- * \see ll_file_put_fast_lock
- */
-static inline int ll_file_get_fast_lock(struct file *file,
- obd_off ppos, obd_off end,
- char *buf, void **cookie, int rw)
-{
- int rc = 0;
- struct page *page;
-
- ENTRY;
-
- if (!ll_region_mapped((unsigned long)buf, end - ppos)) {
- page = find_lock_page(file->f_dentry->d_inode->i_mapping,
- ppos >> CFS_PAGE_SHIFT);
- if (page) {
- if (ll_reget_short_lock(page, rw, ppos, end, cookie))
- rc = 1;
-
- unlock_page(page);
- page_cache_release(page);
- }
- }
-
- RETURN(rc);
-}
-
-/**
- * Releases a reference to a lock taken in a "fast" way.
- *
- * Releases a read or a write (specified by \a rw) lock
- * referenced by \a cookie.
- *
- * \param inode inode to which data belong
- * \param end end of the locked extent
- * \param rw OBD_BRW_READ if requested for reading,
- * OBD_BRW_WRITE if requested for writing
- * \param cookie transparent parameter for passing locking context
- *
- * \post appropriate lock is dereferenced
- *
- * \see ll_file_get_fast_lock
- */
-static inline void ll_file_put_fast_lock(struct inode *inode, obd_off end,
- void *cookie, int rw)
-{
- ll_release_short_lock(inode, end, cookie, rw);
-}
-
-enum ll_lock_style {
- LL_LOCK_STYLE_NOLOCK = 0,
- LL_LOCK_STYLE_FASTLOCK = 1,
- LL_LOCK_STYLE_TREELOCK = 2
-};
-
-/**
- * Checks if requested extent lock is compatible with a lock
- * under a page cache page.
- *
- * Checks if the lock under \a page is compatible with a read or write lock
- * (specified by \a rw) for an extent [\a start , \a end].
- *
- * \param file file under which I/O is processed
- * \param rw OBD_BRW_READ if requested for reading,
- * OBD_BRW_WRITE if requested for writing
- * \param ppos start of the requested extent
- * \param end end of the requested extent
- * \param cookie transparent parameter for passing locking context
- * (only used with LL_LOCK_STYLE_FASTLOCK)
- * \param tree lock tree (only used with LL_LOCK_STYLE_TREELOCK)
- * \param buf userspace buffer for the data
- *
- * \retval LL_LOCK_STYLE_FASTLOCK owned lock is reused through fast lock
- * \retval LL_LOCK_STYLE_TREELOCK got a lock through tree lock
- * \retval LL_LOCK_STYLE_NOLOCK got no lock
- *
- * \see ll_file_put_lock
- */
-static inline int ll_file_get_lock(struct file *file, obd_off ppos,
- obd_off end, char *buf, void **cookie,
- struct ll_lock_tree *tree, int rw)
-{
- int rc;
-
- ENTRY;
-
- if (ll_file_get_fast_lock(file, ppos, end, buf, cookie, rw))
- RETURN(LL_LOCK_STYLE_FASTLOCK);
-
- rc = ll_file_get_tree_lock(tree, file, buf, ppos - end, ppos, end, rw);
- /* rc: 1 for tree lock, 0 for no lock, <0 for error */
- switch (rc) {
- case 1:
- RETURN(LL_LOCK_STYLE_TREELOCK);
- case 0:
- RETURN(LL_LOCK_STYLE_NOLOCK);
- }
-
- /* an error happened if we reached this point, rc = -errno here */
- RETURN(rc);
-}
-
-/**
- * Drops the lock taken by ll_file_get_lock.
- *
- * Releases a read or a write (specified by \a rw) lock
- * referenced by \a tree or \a cookie.
- *
- * \param inode inode to which data belong
- * \param end end of the locked extent
- * \param lockstyle facility through which the lock was taken
- * \param rw OBD_BRW_READ if requested for reading,
- * OBD_BRW_WRITE if requested for writing
- * \param cookie transparent parameter for passing locking context
- * (only used with LL_LOCK_STYLE_FASTLOCK)
- * \param tree lock tree (only used with LL_LOCK_STYLE_TREELOCK)
- *
- * \post appropriate lock is dereferenced
- *
- * \see ll_file_get_lock
- */
-static inline void ll_file_put_lock(struct inode *inode, obd_off end,
- enum ll_lock_style lock_style,
- void *cookie, struct ll_lock_tree *tree,
- int rw)
-
-{
- switch (lock_style) {
- case LL_LOCK_STYLE_TREELOCK:
- ll_tree_unlock(tree);
- break;
- case LL_LOCK_STYLE_FASTLOCK:
- ll_file_put_fast_lock(inode, end, cookie, rw);
- break;
- default:
- CERROR("invalid locking style (%d)\n", lock_style);
- }
-}
-
-static ssize_t ll_file_read(struct file *file, char *buf, size_t count,
- loff_t *ppos)
-{
- struct inode *inode = file->f_dentry->d_inode;
- struct ll_inode_info *lli = ll_i2info(inode);
- struct lov_stripe_md *lsm = lli->lli_smd;
- struct ll_sb_info *sbi = ll_i2sbi(inode);
- struct ll_lock_tree tree;
- struct ost_lvb lvb;
- struct ll_ra_read bead;
- int ra = 0;
- obd_off end;
- ssize_t retval, chunk, sum = 0;
- int lock_style;
- void *cookie;
-
- __u64 kms;
- ENTRY;
- CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p),size="LPSZ",offset=%Ld\n",
- inode->i_ino, inode->i_generation, inode, count, *ppos);
- /* "If nbyte is 0, read() will return 0 and have no other results."
- * -- Single Unix Spec */
- if (count == 0)
- RETURN(0);
-
- ll_stats_ops_tally(sbi, LPROC_LL_READ_BYTES, count);
-
- if (!lsm) {
- /* Read on file with no objects should return zero-filled
- * buffers up to file size (we can get non-zero sizes with
- * mknod + truncate, then opening file for read. This is a
- * common pattern in NFS case, it seems). Bug 6243 */
- int notzeroed;
- /* Since there are no objects on OSTs, we have nothing to get
- * lock on and so we are forced to access inode->i_size
- * unguarded */
-
- /* Read beyond end of file */
- if (*ppos >= i_size_read(inode))
- RETURN(0);
-
- if (count > i_size_read(inode) - *ppos)
- count = i_size_read(inode) - *ppos;
- /* Make sure to correctly adjust the file pos pointer for
- * EFAULT case */
- notzeroed = clear_user(buf, count);
- count -= notzeroed;
- *ppos += count;
- if (!count)
- RETURN(-EFAULT);
- RETURN(count);
- }
-repeat:
- if (sbi->ll_max_rw_chunk != 0) {
- /* first, let's know the end of the current stripe */
- end = *ppos;
- obd_extent_calc(sbi->ll_dt_exp, lsm, OBD_CALC_STRIPE_END, &end);
-
- /* correct, the end is beyond the request */
- if (end > *ppos + count - 1)
- end = *ppos + count - 1;
-
- /* and chunk shouldn't be too large even if striping is wide */
- if (end - *ppos > sbi->ll_max_rw_chunk)
- end = *ppos + sbi->ll_max_rw_chunk - 1;
- } else {
- end = *ppos + count - 1;
- }
-
- lock_style = ll_file_get_lock(file, (obd_off)(*ppos), end,
- buf, &cookie, &tree, OBD_BRW_READ);
- if (lock_style < 0)
- GOTO(out, retval = lock_style);
-
- ll_inode_size_lock(inode, 1);
- /*
- * Consistency guarantees: following possibilities exist for the
- * relation between region being read and real file size at this
- * moment:
- *
- * (A): the region is completely inside of the file;
- *
- * (B-x): x bytes of region are inside of the file, the rest is
- * outside;
- *
- * (C): the region is completely outside of the file.
- *
- * This classification is stable under DLM lock acquired by
- * ll_tree_lock() above, because to change class, other client has to
- * take DLM lock conflicting with our lock. Also, any updates to
- * ->i_size by other threads on this client are serialized by
- * ll_inode_size_lock(). This guarantees that short reads are handled
- * correctly in the face of concurrent writes and truncates.
- */
- inode_init_lvb(inode, &lvb);
- obd_merge_lvb(sbi->ll_dt_exp, lsm, &lvb, 1);
- kms = lvb.lvb_size;
- if (*ppos + count - 1 > kms) {
- /* A glimpse is necessary to determine whether we return a
- * short read (B) or some zeroes at the end of the buffer (C) */
- ll_inode_size_unlock(inode, 1);
- retval = ll_glimpse_size(inode, LDLM_FL_BLOCK_GRANTED);
- if (retval) {
- if (lock_style != LL_LOCK_STYLE_NOLOCK)
- ll_file_put_lock(inode, end, lock_style,
- cookie, &tree, OBD_BRW_READ);
- goto out;
- }
- } else {
- /* region is within kms and, hence, within real file size (A).
- * We need to increase i_size to cover the read region so that
- * generic_file_read() will do its job, but that doesn't mean
- * the kms size is _correct_, it is only the _minimum_ size.
- * If someone does a stat they will get the correct size which
- * will always be >= the kms value here. b=11081 */
- if (i_size_read(inode) < kms)
- i_size_write(inode, kms);
- ll_inode_size_unlock(inode, 1);
- }
-
- chunk = end - *ppos + 1;
- CDEBUG(D_INODE, "Read ino %lu, "LPSZ" bytes, offset %lld, i_size %llu\n",
- inode->i_ino, chunk, *ppos, i_size_read(inode));
-
- if (lock_style != LL_LOCK_STYLE_NOLOCK) {
- /* turn off the kernel's read-ahead */
- file->f_ra.ra_pages = 0;
-
- /* initialize read-ahead window once per syscall */
- if (ra == 0) {
- ra = 1;
- bead.lrr_start = *ppos >> CFS_PAGE_SHIFT;
- bead.lrr_count = (count + CFS_PAGE_SIZE - 1) >> CFS_PAGE_SHIFT;
- ll_ra_read_in(file, &bead);
- }
-
- /* BUG: 5972 */
- file_accessed(file);
- retval = generic_file_read(file, buf, chunk, ppos);
- ll_file_put_lock(inode, end, lock_style, cookie, &tree,
- OBD_BRW_READ);
- } else {
- retval = ll_file_lockless_io(file, buf, chunk, ppos, READ);
- }
-
- ll_rw_stats_tally(sbi, current->pid, file, chunk, 0);
-
- if (retval > 0) {
- buf += retval;
- count -= retval;
- sum += retval;
- if (retval == chunk && count > 0)
- goto repeat;
- }
-
- out:
- if (ra != 0)
- ll_ra_read_ex(file, &bead);
- retval = (sum > 0) ? sum : retval;
- RETURN(retval);
-}
-
-/*
- * Write to a file (through the page cache).
- */
-static ssize_t ll_file_write(struct file *file, const char *buf, size_t count,
- loff_t *ppos)
-{
- struct inode *inode = file->f_dentry->d_inode;
- struct ll_sb_info *sbi = ll_i2sbi(inode);
- struct lov_stripe_md *lsm = ll_i2info(inode)->lli_smd;
- struct ll_lock_tree tree;
- loff_t maxbytes = ll_file_maxbytes(inode);
- loff_t lock_start, lock_end, end;
- ssize_t retval, chunk, sum = 0;
- int tree_locked;
- ENTRY;
-
- CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p),size="LPSZ",offset=%Ld\n",
- inode->i_ino, inode->i_generation, inode, count, *ppos);
-
- SIGNAL_MASK_ASSERT(); /* XXX BUG 1511 */
-
- /* POSIX, but surprised the VFS doesn't check this already */
- if (count == 0)
- RETURN(0);
-
- /* If file was opened for LL_IOC_LOV_SETSTRIPE but the ioctl wasn't
- * called on the file, don't fail the below assertion (bug 2388). */
- if (file->f_flags & O_LOV_DELAY_CREATE &&
- ll_i2info(inode)->lli_smd == NULL)
- RETURN(-EBADF);
-
- LASSERT(ll_i2info(inode)->lli_smd != NULL);
-
- down(&ll_i2info(inode)->lli_write_sem);
-
-repeat:
- chunk = 0; /* just to fix gcc's warning */
- end = *ppos + count - 1;
-
- if (file->f_flags & O_APPEND) {
- lock_start = 0;
- lock_end = OBD_OBJECT_EOF;
- } else if (sbi->ll_max_rw_chunk != 0) {
- /* first, let's know the end of the current stripe */
- end = *ppos;
- obd_extent_calc(sbi->ll_dt_exp, lsm, OBD_CALC_STRIPE_END,
- (obd_off *)&end);
-
- /* correct, the end is beyond the request */
- if (end > *ppos + count - 1)
- end = *ppos + count - 1;
-
- /* and chunk shouldn't be too large even if striping is wide */
- if (end - *ppos > sbi->ll_max_rw_chunk)
- end = *ppos + sbi->ll_max_rw_chunk - 1;
- lock_start = *ppos;
- lock_end = end;
- } else {
- lock_start = *ppos;
- lock_end = *ppos + count - 1;
- }
-
- tree_locked = ll_file_get_tree_lock(&tree, file, buf, count,
- lock_start, lock_end, OBD_BRW_WRITE);
- if (tree_locked < 0)
- GOTO(out, retval = tree_locked);
-
- /* This is ok, g_f_w will overwrite this under i_sem if it races
- * with a local truncate, it just makes our maxbyte checking easier.
- * The i_size value gets updated in ll_extent_lock() as a consequence
- * of the [0,EOF] extent lock we requested above. */
- if (file->f_flags & O_APPEND) {
- *ppos = i_size_read(inode);
- end = *ppos + count - 1;
- }
-
- if (*ppos >= maxbytes) {
- send_sig(SIGXFSZ, current, 0);
- GOTO(out_unlock, retval = -EFBIG);
- }
- if (end > maxbytes - 1)
- end = maxbytes - 1;
-
- /* generic_file_write handles O_APPEND after getting i_mutex */
- chunk = end - *ppos + 1;
- CDEBUG(D_INFO, "Writing inode %lu, "LPSZ" bytes, offset %Lu\n",
- inode->i_ino, chunk, *ppos);
- if (tree_locked)
- retval = generic_file_write(file, buf, chunk, ppos);
- else
- retval = ll_file_lockless_io(file, (char*)buf, chunk,
- ppos, WRITE);
- ll_rw_stats_tally(ll_i2sbi(inode), current->pid, file, chunk, 1);
-
-out_unlock:
- if (tree_locked)
- ll_tree_unlock(&tree);
-
-out:
- if (retval > 0) {
- buf += retval;
- count -= retval;
- sum += retval;
- if (retval == chunk && count > 0)
- goto repeat;
- }
-
- up(&ll_i2info(inode)->lli_write_sem);
-
- retval = (sum > 0) ? sum : retval;
- ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_WRITE_BYTES,
- retval > 0 ? retval : 0);
- RETURN(retval);
-}
-
-/*
- * Send file content (through pagecache) somewhere with helper
- */
-static ssize_t ll_file_sendfile(struct file *in_file, loff_t *ppos,size_t count,
- read_actor_t actor, void *target)
-{
- struct inode *inode = in_file->f_dentry->d_inode;
- struct ll_inode_info *lli = ll_i2info(inode);
- struct lov_stripe_md *lsm = lli->lli_smd;
- struct ll_lock_tree tree;
- struct ll_lock_tree_node *node;
- struct ost_lvb lvb;
- struct ll_ra_read bead;
- int rc;
- ssize_t retval;
- __u64 kms;
- ENTRY;
- CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p),size="LPSZ",offset=%Ld\n",
- inode->i_ino, inode->i_generation, inode, count, *ppos);
-
- /* "If nbyte is 0, read() will return 0 and have no other results."
- * -- Single Unix Spec */
- if (count == 0)
- RETURN(0);
-
- ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_READ_BYTES, count);
- /* turn off the kernel's read-ahead */
- in_file->f_ra.ra_pages = 0;
-
- /* File with no objects, nothing to lock */
- if (!lsm)
- RETURN(generic_file_sendfile(in_file, ppos, count, actor, target));
-
- node = ll_node_from_inode(inode, *ppos, *ppos + count - 1, LCK_PR);
- if (IS_ERR(node))
- RETURN(PTR_ERR(node));
-
- tree.lt_fd = LUSTRE_FPRIVATE(in_file);
- rc = ll_tree_lock(&tree, node, NULL, count,
- in_file->f_flags & O_NONBLOCK?LDLM_FL_BLOCK_NOWAIT:0);
- if (rc != 0)
- RETURN(rc);
-
- ll_clear_file_contended(inode);
- ll_inode_size_lock(inode, 1);
- /*
- * Consistency guarantees: following possibilities exist for the
- * relation between region being read and real file size at this
- * moment:
- *
- * (A): the region is completely inside of the file;
- *
- * (B-x): x bytes of region are inside of the file, the rest is
- * outside;
- *
- * (C): the region is completely outside of the file.
- *
- * This classification is stable under DLM lock acquired by
- * ll_tree_lock() above, because to change class, other client has to
- * take DLM lock conflicting with our lock. Also, any updates to
- * ->i_size by other threads on this client are serialized by
- * ll_inode_size_lock(). This guarantees that short reads are handled
- * correctly in the face of concurrent writes and truncates.
- */
- inode_init_lvb(inode, &lvb);
- obd_merge_lvb(ll_i2sbi(inode)->ll_dt_exp, lsm, &lvb, 1);
- kms = lvb.lvb_size;
- if (*ppos + count - 1 > kms) {
- /* A glimpse is necessary to determine whether we return a
- * short read (B) or some zeroes at the end of the buffer (C) */
- ll_inode_size_unlock(inode, 1);
- retval = ll_glimpse_size(inode, LDLM_FL_BLOCK_GRANTED);
- if (retval)
- goto out;
- } else {
- /* region is within kms and, hence, within real file size (A) */
- i_size_write(inode, kms);
- ll_inode_size_unlock(inode, 1);
- }
-
- CDEBUG(D_INFO, "Send ino %lu, "LPSZ" bytes, offset %lld, i_size %llu\n",
- inode->i_ino, count, *ppos, i_size_read(inode));
-
- bead.lrr_start = *ppos >> CFS_PAGE_SHIFT;
- bead.lrr_count = (count + CFS_PAGE_SIZE - 1) >> CFS_PAGE_SHIFT;
- ll_ra_read_in(in_file, &bead);
- /* BUG: 5972 */
- file_accessed(in_file);
- retval = generic_file_sendfile(in_file, ppos, count, actor, target);
- ll_ra_read_ex(in_file, &bead);
-
- out:
- ll_tree_unlock(&tree);
- RETURN(retval);
-}
-
-static int ll_lov_recreate_obj(struct inode *inode, struct file *file,
- unsigned long arg)
-{
- struct ll_inode_info *lli = ll_i2info(inode);
- struct obd_export *exp = ll_i2dtexp(inode);
- struct ll_recreate_obj ucreatp;
- struct obd_trans_info oti = { 0 };
- struct obdo *oa = NULL;
- int lsm_size;
- int rc = 0;
- struct lov_stripe_md *lsm, *lsm2;
- ENTRY;
-
- if (!capable (CAP_SYS_ADMIN))
- RETURN(-EPERM);
-
- rc = copy_from_user(&ucreatp, (struct ll_recreate_obj *)arg,
- sizeof(struct ll_recreate_obj));
- if (rc) {
- RETURN(-EFAULT);
- }
- OBDO_ALLOC(oa);
- if (oa == NULL)
- RETURN(-ENOMEM);
-
- down(&lli->lli_size_sem);
- lsm = lli->lli_smd;
- if (lsm == NULL)
- GOTO(out, rc = -ENOENT);
- lsm_size = sizeof(*lsm) + (sizeof(struct lov_oinfo) *
- (lsm->lsm_stripe_count));
-
- OBD_ALLOC(lsm2, lsm_size);
- if (lsm2 == NULL)
- GOTO(out, rc = -ENOMEM);
-
- oa->o_id = ucreatp.lrc_id;
- oa->o_gr = ucreatp.lrc_group;
- oa->o_nlink = ucreatp.lrc_ost_idx;
- oa->o_flags |= OBD_FL_RECREATE_OBJS;
- oa->o_valid = OBD_MD_FLID | OBD_MD_FLFLAGS | OBD_MD_FLGROUP;
- obdo_from_inode(oa, inode, OBD_MD_FLTYPE | OBD_MD_FLATIME |
- OBD_MD_FLMTIME | OBD_MD_FLCTIME);
-
- memcpy(lsm2, lsm, lsm_size);
- rc = obd_create(exp, oa, &lsm2, &oti);
-
- OBD_FREE(lsm2, lsm_size);
- GOTO(out, rc);
-out:
- up(&lli->lli_size_sem);
- OBDO_FREE(oa);
- return rc;