if (plen > len)
plen = len;
- lnb->offset = offset;
- /* lnb->lnb_page_offset = poff; */
+ lnb->lnb_file_offset = offset;
+ lnb->lnb_page_offset = poff;
lnb->len = plen;
/* lb->flags = rnb->flags; */
lnb->flags = 0;
* needs to keep the pages all aligned properly. */
lnb->dentry = (void *) obj;
- lnb->page = osd_get_page(d, lnb->offset, rw);
+ lnb->page = osd_get_page(d, lnb->lnb_file_offset, rw);
if (lnb->page == NULL)
GOTO(cleanup, rc = -ENOMEM);
long off;
char *p = kmap(lnb[i].page);
- off = lnb[i].offset;
- if (off)
- memset(p, 0, off);
- off = lnb[i].offset + lnb[i].len;
- off &= ~CFS_PAGE_MASK;
+ off = lnb[i].lnb_page_offset;
+ if (off)
+ memset(p, 0, off);
+ off = (lnb[i].lnb_page_offset + lnb[i].len) &
+ ~CFS_PAGE_MASK;
if (off)
memset(p + off, 0, CFS_PAGE_SIZE - off);
kunmap(lnb[i].page);
RETURN(rc);
}
+/* Check if a block is allocated or not */
+static int osd_is_mapped(struct inode *inode, obd_size offset)
+{
+ sector_t (*fs_bmap)(struct address_space *, sector_t);
+
+ fs_bmap = inode->i_mapping->a_ops->bmap;
+
+ /* We can't know if we are overwriting or not */
+ if (unlikely(fs_bmap == NULL))
+ return 0;
+
+ if (i_size_read(inode) == 0)
+ return 0;
+
+ /* Beyond EOF, must not be mapped */
+ if (((i_size_read(inode) - 1) >> inode->i_blkbits) <
+ (offset >> inode->i_blkbits))
+ return 0;
+
+ if (fs_bmap(inode->i_mapping, offset >> inode->i_blkbits) == 0)
+ return 0;
+
+ return 1;
+}
+
static int osd_declare_write_commit(const struct lu_env *env,
struct dt_object *dt,
struct niobuf_local *lnb, int npages,
int depth;
int i;
int newblocks;
- int old;
+ int rc = 0;
+ int flags = 0;
+ bool ignore_quota = false;
+ long long quota_space = 0;
+ ENTRY;
LASSERT(handle != NULL);
oh = container_of0(handle, struct osd_thandle, ot_super);
LASSERT(oh->ot_handle == NULL);
- old = oh->ot_credits;
newblocks = npages;
/* calculate number of extents (probably better to pass nb) */
- for (i = 1; i < npages; i++)
- if (lnb[i].offset !=
- lnb[i - 1].offset + lnb[i - 1].len)
- extents++;
+ for (i = 0; i < npages; i++) {
+ if (i && lnb[i].lnb_file_offset !=
+ lnb[i - 1].lnb_file_offset + lnb[i - 1].len)
+ extents++;
+
+ if (!osd_is_mapped(inode, lnb[i].lnb_file_offset))
+ quota_space += CFS_PAGE_SIZE;
+
+ /* ignore quota for the whole request if any page is from
+ * client cache or written by root.
+ *
+ * XXX we could handle this on per-lnb basis as done by
+ * grant. */
+ if ((lnb[i].flags & OBD_BRW_NOQUOTA) ||
+ !(lnb[i].flags & OBD_BRW_SYNC))
+ ignore_quota = true;
+ }
/*
* each extent can go into new leaf causing a split
oh->ot_credits += depth * extents;
}
+ /* quota space for metadata blocks */
+ quota_space += depth * extents * LDISKFS_BLOCK_SIZE(osd_sb(osd));
+
+ /* quota space should be reported in 1K blocks */
+ quota_space = toqb(quota_space);
+
/* each new block can go in different group (bitmap + gd) */
/* we can't dirty more bitmap blocks than exist */
else
oh->ot_credits += newblocks;
- RETURN(0);
-}
-
-/* Check if a block is allocated or not */
-static int osd_is_mapped(struct inode *inode, obd_size offset)
-{
- sector_t (*fs_bmap)(struct address_space *, sector_t);
+ /* make sure the over quota flags were not set */
+ lnb[0].flags &= ~(OBD_BRW_OVER_USRQUOTA | OBD_BRW_OVER_GRPQUOTA);
- fs_bmap = inode->i_mapping->a_ops->bmap;
+ rc = osd_declare_inode_qid(env, inode->i_uid, inode->i_gid,
+ quota_space, oh, true, true, &flags,
+ ignore_quota);
- /* We can't know if we are overwriting or not */
- if (fs_bmap == NULL)
- return 0;
+ /* we need only to store the overquota flags in the first lnb for
+ * now, once we support multiple objects BRW, this code needs be
+ * revised. */
+ if (flags & QUOTA_FL_OVER_USRQUOTA)
+ lnb[0].flags |= OBD_BRW_OVER_USRQUOTA;
+ if (flags & QUOTA_FL_OVER_GRPQUOTA)
+ lnb[0].flags |= OBD_BRW_OVER_GRPQUOTA;
- if (fs_bmap(inode->i_mapping, offset >> inode->i_blkbits) == 0)
- return 0;
-
- return 1;
+ RETURN(rc);
}
+/* Check if a block is allocated or not */
static int osd_write_commit(const struct lu_env *env, struct dt_object *dt,
struct niobuf_local *lnb, int npages,
struct thandle *thandle)
osd_init_iobuf(osd, iobuf, 1);
isize = i_size_read(inode);
+ ll_vfs_dq_init(inode);
for (i = 0; i < npages; i++) {
if (lnb[i].rc == -ENOSPC &&
- osd_is_mapped(inode, lnb[i].offset)) {
+ osd_is_mapped(inode, lnb[i].lnb_file_offset)) {
/* Allow the write to proceed if overwriting an
* existing block */
lnb[i].rc = 0;
LASSERT(PageLocked(lnb[i].page));
LASSERT(!PageWriteback(lnb[i].page));
- if (lnb[i].offset + lnb[i].len > isize)
- isize = lnb[i].offset + lnb[i].len;
+ if (lnb[i].lnb_file_offset + lnb[i].len > isize)
+ isize = lnb[i].lnb_file_offset + lnb[i].len;
/*
* Since write and truncate are serialized by oo_sem, even
cfs_gettimeofday(&start);
for (i = 0; i < npages; i++) {
- if (i_size_read(inode) <= lnb[i].offset)
+ if (i_size_read(inode) <= lnb[i].lnb_file_offset)
/* If there's no more data, abort early.
* lnb->rc == 0, so it's easy to detect later. */
break;
if (i_size_read(inode) <
- lnb[i].offset + lnb[i].len - 1)
- lnb[i].rc = i_size_read(inode) - lnb[i].offset;
+ lnb[i].lnb_file_offset + lnb[i].len - 1)
+ lnb[i].rc = i_size_read(inode) - lnb[i].lnb_file_offset;
else
lnb[i].rc = lnb[i].len;
m += lnb[i].len;
/* prevent reading after eof */
cfs_spin_lock(&inode->i_lock);
if (i_size_read(inode) < *offs + size) {
- size = i_size_read(inode) - *offs;
- cfs_spin_unlock(&inode->i_lock);
- if (size < 0) {
- CDEBUG(D_EXT2, "size %llu is too short to read @%llu\n",
- i_size_read(inode), *offs);
- return -EBADR;
- } else if (size == 0) {
- return 0;
- }
+ loff_t diff = i_size_read(inode) - *offs;
+ cfs_spin_unlock(&inode->i_lock);
+ if (diff < 0) {
+ CDEBUG(D_EXT2, "size %llu is too short to read @%llu\n",
+ i_size_read(inode), *offs);
+ return -EBADR;
+ } else if (diff == 0) {
+ return 0;
+ } else {
+ size = diff;
+ }
} else {
cfs_spin_unlock(&inode->i_lock);
}
{
struct osd_thandle *oh;
int credits;
+ struct inode *inode;
+ int rc;
+ ENTRY;
LASSERT(handle != NULL);
OSD_DECLARE_OP(oh, write);
oh->ot_credits += credits;
- if (osd_dt_obj(dt)->oo_inode == NULL)
- return 0;
+ inode = osd_dt_obj(dt)->oo_inode;
- osd_declare_qid(dt, oh, USRQUOTA, osd_dt_obj(dt)->oo_inode->i_uid,
- osd_dt_obj(dt)->oo_inode);
- osd_declare_qid(dt, oh, GRPQUOTA, osd_dt_obj(dt)->oo_inode->i_gid,
- osd_dt_obj(dt)->oo_inode);
- return 0;
+ /* we may declare write to non-exist llog */
+ if (inode == NULL)
+ RETURN(0);
+
+ /* dt_declare_write() is usually called for system objects, such
+ * as llog or last_rcvd files. We needn't enforce quota on those
+ * objects, so always set the lqi_space as 0. */
+ rc = osd_declare_inode_qid(env, inode->i_uid, inode->i_gid, 0, oh,
+ true, true, NULL, false);
+ RETURN(rc);
}
static int osd_ldiskfs_writelink(struct inode *inode, char *buffer, int buflen)
struct inode *inode = osd_dt_obj(dt)->oo_inode;
struct osd_thandle *oh;
ssize_t result;
-#ifdef HAVE_QUOTA_SUPPORT
- cfs_cap_t save = cfs_curproc_cap_pack();
-#endif
int is_link;
LASSERT(dt_object_exists(dt));
oh = container_of(handle, struct osd_thandle, ot_super);
LASSERT(oh->ot_handle->h_transaction != NULL);
-#ifdef HAVE_QUOTA_SUPPORT
- if (ignore_quota)
- cfs_cap_raise(CFS_CAP_SYS_RESOURCE);
- else
- cfs_cap_lower(CFS_CAP_SYS_RESOURCE);
-#endif
/* Write small symlink to inode body as we need to maintain correct
* on-disk symlinks for ldiskfs.
* Note: the buf->lb_buf contains a NUL terminator while buf->lb_len
result = osd_ldiskfs_write_record(inode, buf->lb_buf,
buf->lb_len, is_link, pos,
oh->ot_handle);
-#ifdef HAVE_QUOTA_SUPPORT
- cfs_curproc_cap_unpack(save);
-#endif
if (result == 0)
result = buf->lb_len;
return result;
__u64 start, __u64 end, struct thandle *th)
{
struct osd_thandle *oh;
+ struct inode *inode;
+ int rc;
ENTRY;
LASSERT(th);
oh->ot_credits += osd_dto_credits_noquota[DTO_ATTR_SET_BASE];
oh->ot_credits += 3;
- RETURN(0);
+ inode = osd_dt_obj(dt)->oo_inode;
+ LASSERT(inode);
+
+ rc = osd_declare_inode_qid(env, inode->i_uid, inode->i_gid, 0, oh,
+ true, true, NULL, false);
+ RETURN(rc);
}
static int osd_punch(const struct lu_env *env, struct dt_object *dt,