hash = fd->fd_dir.lfd_next;
} else {
- struct ll_inode_info *lli = ll_i2info(inode);
-
- cfs_spin_lock(&lli->lli_sa_lock);
- if (lli->lli_sai)
- LASSERT(lli->lli_sai->sai_pid == cfs_curproc_pid());
- else
- LASSERT(lli->lli_opendir_pid == cfs_curproc_pid());
- hash = lli->lli_sa_pos;
- cfs_spin_unlock(&lli->lli_sa_lock);
+ hash = ll_i2info(inode)->lli_sa_pos;
}
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p) hash "LPU64"\n",
inode->i_ino, inode->i_generation, inode, hash);
SetPageChecked(page);
}
-static void ll_release_page(struct page *page, __u64 hash,
- __u64 start, __u64 end)
+void ll_release_page(struct page *page, int remove)
{
kunmap(page);
- lock_page(page);
- if (likely(page->mapping != NULL)) {
- ll_truncate_complete_page(page);
- unlock_page(page);
- } else {
+ if (remove) {
+ lock_page(page);
+ if (likely(page->mapping != NULL))
+ truncate_complete_page(page->mapping, page);
unlock_page(page);
- CWARN("NULL mapping page %p, truncated by others: "
- "hash("LPX64") | start("LPX64") | end("LPX64")\n",
- page, hash, start, end);
}
page_cache_release(page);
}
LPX64",hash = "LPX64"\n", *start, *end, *hash);
CDEBUG(D_VFSTRACE, "page %lu [%llu %llu], hash "LPU64"\n",
offset, *start, *end, *hash);
- if (*hash > *end || (*end != *start && *hash == *end)) {
+ if (*hash > *end) {
+ ll_release_page(page, 0);
+ page = NULL;
+ } else if (*end != *start && *hash == *end) {
/*
* upon hash collision, remove this page,
* otherwise put page reference, and
* ll_get_dir_page() will issue RPC to fetch
* the page we want.
*/
- if (dp->ldp_flags & cpu_to_le32(LDF_COLLIDE)) {
- ll_release_page(page, *hash, *start, *end);
- } else {
- cfs_kunmap(page);
- page_cache_release(page);
- }
+ ll_release_page(page,
+ le32_to_cpu(dp->ldp_flags) & LDF_COLLIDE);
page = NULL;
}
} else {
}
struct page *ll_get_dir_page(struct file *filp, struct inode *dir, __u64 hash,
- int exact, struct ll_dir_chain *chain)
+ struct ll_dir_chain *chain)
{
ldlm_policy_data_t policy = {.l_inodebits = {MDS_INODELOCK_UPDATE} };
struct address_space *mapping = dir->i_mapping;
CERROR("dir page locate: "DFID" at "LPU64": rc %ld\n",
PFID(ll_inode2fid(dir)), lhash, PTR_ERR(page));
GOTO(out_unlock, page);
- }
-
- if (page != NULL) {
+ } else if (page != NULL) {
/*
* XXX nikita: not entirely correct handling of a corner case:
* suppose hash chain of entries with hash value HASH crosses
* it as an "overflow" page. 1. invalidate all pages at
* once. 2. use HASH|1 as an index for P1.
*/
- if (exact && lhash != start) {
- /*
- * readdir asked for a page starting _exactly_ from
- * given hash, but cache contains stale page, with
- * entries with smaller hash values. Stale page should
- * be invalidated, and new one fetched.
- */
- CDEBUG(D_OTHER, "Stale readpage page %p: "
- "start = "LPX64",end = "LPX64"hash ="LPX64"\n",
- page, start, end, lhash);
- ll_release_page(page, lhash, start, end);
- } else {
- GOTO(hash_collision, page);
- }
+ GOTO(hash_collision, page);
}
page = read_cache_page(mapping, hash_x_index(hash, hash64),
return page;
fail:
- ll_put_page(page);
+ ll_release_page(page, 1);
page = ERR_PTR(-EIO);
goto out_unlock;
}
struct page *page;
struct ll_dir_chain chain;
int done;
- int shift;
int rc;
ENTRY;
rc = 0;
done = 0;
- shift = 0;
ll_dir_chain_init(&chain);
fd->fd_dir.lfd_next = pos;
- page = ll_get_dir_page(filp, inode, pos, 0, &chain);
+ page = ll_get_dir_page(filp, inode, pos, &chain);
while (rc == 0 && !done) {
struct lu_dirpage *dp;
lhash, ino, type);
}
next = le64_to_cpu(dp->ldp_hash_end);
- ll_put_page(page);
if (!done) {
pos = next;
if (pos == MDS_DIR_END_OFF) {
* End of directory reached.
*/
done = 1;
+ ll_release_page(page, 0);
} else if (1 /* chain is exhausted*/) {
/*
* Normal case: continue to the next
* page.
*/
+ ll_release_page(page,
+ le32_to_cpu(dp->ldp_flags) &
+ LDF_COLLIDE);
fd->fd_dir.lfd_next = pos;
page = ll_get_dir_page(filp, inode, pos,
- 1, &chain);
+ &chain);
} else {
/*
* go into overflow page.
*/
+ LASSERT(le32_to_cpu(dp->ldp_flags) &
+ LDF_COLLIDE);
+ ll_release_page(page, 1);
}
} else {
pos = hash;
+ ll_release_page(page, 0);
}
} else {
rc = PTR_ERR(page);
lum_size = sizeof(struct lov_user_md_v3);
break;
}
- default: {
+ default: {
CDEBUG(D_IOCTL, "bad userland LOV MAGIC:"
" %#08x != %#08x nor %#08x\n",
lump->lmm_magic, LOV_USER_MAGIC_V1,
op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL,
0, lmmsize, LUSTRE_OPC_ANY,
NULL);
- if (op_data == NULL)
- RETURN(-ENOMEM);
+ if (IS_ERR(op_data))
+ RETURN(PTR_ERR(op_data));
op_data->op_valid = OBD_MD_FLEASIZE | OBD_MD_FLDIREA;
rc = md_getattr(sbi->ll_md_exp, op_data, &req);
op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0,
0, LUSTRE_OPC_ANY, NULL);
- if (op_data == NULL)
- RETURN(-ENOMEM);
+ if (IS_ERR(op_data))
+ RETURN(PTR_ERR(op_data));
op_data->op_valid |= OBD_MD_MDTIDX;
rc = md_getattr(sbi->ll_md_exp, op_data, NULL);
return rc;
}
+static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl)
+{
+ int cmd = qctl->qc_cmd;
+ int type = qctl->qc_type;
+ int id = qctl->qc_id;
+ int valid = qctl->qc_valid;
+ int rc = 0;
+ ENTRY;
+
+ switch (cmd) {
+ case LUSTRE_Q_INVALIDATE:
+ case LUSTRE_Q_FINVALIDATE:
+ case Q_QUOTAON:
+ case Q_QUOTAOFF:
+ case Q_SETQUOTA:
+ case Q_SETINFO:
+ if (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
+ sbi->ll_flags & LL_SBI_RMT_CLIENT)
+ RETURN(-EPERM);
+ break;
+ case Q_GETQUOTA:
+ if (((type == USRQUOTA && cfs_curproc_euid() != id) ||
+ (type == GRPQUOTA && !in_egroup_p(id))) &&
+ (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
+ sbi->ll_flags & LL_SBI_RMT_CLIENT))
+ RETURN(-EPERM);
+ break;
+ case Q_GETINFO:
+ break;
+ default:
+ CERROR("unsupported quotactl op: %#x\n", cmd);
+ RETURN(-ENOTTY);
+ }
+
+ if (valid != QC_GENERAL) {
+ if (sbi->ll_flags & LL_SBI_RMT_CLIENT)
+ RETURN(-EOPNOTSUPP);
+
+ if (cmd == Q_GETINFO)
+ qctl->qc_cmd = Q_GETOINFO;
+ else if (cmd == Q_GETQUOTA)
+ qctl->qc_cmd = Q_GETOQUOTA;
+ else
+ RETURN(-EINVAL);
+
+ switch (valid) {
+ case QC_MDTIDX:
+ rc = obd_iocontrol(OBD_IOC_QUOTACTL, sbi->ll_md_exp,
+ sizeof(*qctl), qctl, NULL);
+ break;
+ case QC_OSTIDX:
+ rc = obd_iocontrol(OBD_IOC_QUOTACTL, sbi->ll_dt_exp,
+ sizeof(*qctl), qctl, NULL);
+ break;
+ case QC_UUID:
+ rc = obd_iocontrol(OBD_IOC_QUOTACTL, sbi->ll_md_exp,
+ sizeof(*qctl), qctl, NULL);
+ if (rc == -EAGAIN)
+ rc = obd_iocontrol(OBD_IOC_QUOTACTL,
+ sbi->ll_dt_exp,
+ sizeof(*qctl), qctl, NULL);
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+
+ if (rc)
+ RETURN(rc);
+
+ qctl->qc_cmd = cmd;
+ } else {
+ struct obd_quotactl *oqctl;
+
+ OBD_ALLOC_PTR(oqctl);
+ if (oqctl == NULL)
+ RETURN(-ENOMEM);
+
+ QCTL_COPY(oqctl, qctl);
+ rc = obd_quotactl(sbi->ll_md_exp, oqctl);
+ if (rc) {
+ if (rc != -EALREADY && cmd == Q_QUOTAON) {
+ oqctl->qc_cmd = Q_QUOTAOFF;
+ obd_quotactl(sbi->ll_md_exp, oqctl);
+ }
+ OBD_FREE_PTR(oqctl);
+ RETURN(rc);
+ }
+ /* If QIF_SPACE is not set, client should collect the
+ * space usage from OSSs by itself */
+ if (cmd == Q_GETQUOTA &&
+ !(oqctl->qc_dqblk.dqb_valid & QIF_SPACE) &&
+ !oqctl->qc_dqblk.dqb_curspace) {
+ struct obd_quotactl *oqctl_tmp;
+
+ OBD_ALLOC_PTR(oqctl_tmp);
+ if (oqctl_tmp == NULL)
+ GOTO(out, rc = -ENOMEM);
+
+ oqctl_tmp->qc_cmd = Q_GETOQUOTA;
+ oqctl_tmp->qc_id = oqctl->qc_id;
+ oqctl_tmp->qc_type = oqctl->qc_type;
+
+ /* collect space usage from OSTs */
+ oqctl_tmp->qc_dqblk.dqb_curspace = 0;
+ rc = obd_quotactl(sbi->ll_dt_exp, oqctl_tmp);
+ if (!rc || rc == -EREMOTEIO) {
+ oqctl->qc_dqblk.dqb_curspace =
+ oqctl_tmp->qc_dqblk.dqb_curspace;
+ oqctl->qc_dqblk.dqb_valid |= QIF_SPACE;
+ }
+
+ /* collect space & inode usage from MDTs */
+ oqctl_tmp->qc_dqblk.dqb_curspace = 0;
+ oqctl_tmp->qc_dqblk.dqb_curinodes = 0;
+ rc = obd_quotactl(sbi->ll_md_exp, oqctl_tmp);
+ if (!rc || rc == -EREMOTEIO) {
+ oqctl->qc_dqblk.dqb_curspace +=
+ oqctl_tmp->qc_dqblk.dqb_curspace;
+ oqctl->qc_dqblk.dqb_curinodes =
+ oqctl_tmp->qc_dqblk.dqb_curinodes;
+ oqctl->qc_dqblk.dqb_valid |= QIF_INODES;
+ } else {
+ oqctl->qc_dqblk.dqb_valid &= ~QIF_SPACE;
+ }
+
+ OBD_FREE_PTR(oqctl_tmp);
+ }
+out:
+ QCTL_COPY(qctl, oqctl);
+ OBD_FREE_PTR(oqctl);
+ }
+
+ RETURN(rc);
+}
+
static int ll_dir_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
op_data = ll_prep_md_op_data(NULL, inode, NULL, filename, namelen,
0, LUSTRE_OPC_ANY, NULL);
- if (op_data == NULL)
- GOTO(out_free, rc = -ENOMEM);
+ if (IS_ERR(op_data))
+ GOTO(out_free, rc = PTR_ERR(op_data));
op_data->op_valid = OBD_MD_FLID;
rc = md_getattr_name(sbi->ll_md_exp, op_data, &request);
OBD_FREE_PTR(check);
RETURN(rc);
}
- case OBD_IOC_QUOTACTL: {
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2,7,50,0)
+ case LL_IOC_QUOTACTL_18: {
+ /* copy the old 1.x quota struct for internal use, then copy
+ * back into old format struct. For 1.8 compatibility. */
+ struct if_quotactl_18 *qctl_18;
+ struct if_quotactl *qctl_20;
+
+ OBD_ALLOC_PTR(qctl_18);
+ if (!qctl_18)
+ RETURN(-ENOMEM);
+
+ OBD_ALLOC_PTR(qctl_20);
+ if (!qctl_20)
+ GOTO(out_quotactl_18, rc = -ENOMEM);
+
+ if (cfs_copy_from_user(qctl_18, (void *)arg, sizeof(*qctl_18)))
+ GOTO(out_quotactl_20, rc = -ENOMEM);
+
+ QCTL_COPY(qctl_20, qctl_18);
+ qctl_20->qc_idx = 0;
+
+ /* XXX: dqb_valid was borrowed as a flag to mark that
+ * only mds quota is wanted */
+ if (qctl_18->qc_cmd == Q_GETQUOTA &&
+ qctl_18->qc_dqblk.dqb_valid) {
+ qctl_20->qc_valid = QC_MDTIDX;
+ qctl_20->qc_dqblk.dqb_valid = 0;
+ } else if (qctl_18->obd_uuid.uuid[0] != '\0') {
+ qctl_20->qc_valid = QC_UUID;
+ qctl_20->obd_uuid = qctl_18->obd_uuid;
+ } else {
+ qctl_20->qc_valid = QC_GENERAL;
+ }
+
+ rc = quotactl_ioctl(sbi, qctl_20);
+
+ if (rc == 0) {
+ QCTL_COPY(qctl_18, qctl_20);
+ qctl_18->obd_uuid = qctl_20->obd_uuid;
+
+ if (cfs_copy_to_user((void *)arg, qctl_18,
+ sizeof(*qctl_18)))
+ rc = -EFAULT;
+ }
+
+ out_quotactl_20:
+ OBD_FREE_PTR(qctl_20);
+ out_quotactl_18:
+ OBD_FREE_PTR(qctl_18);
+ RETURN(rc);
+ }
+#else
+#warning "remove old LL_IOC_QUOTACTL_18 compatibility code"
+#endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2,7,50,0) */
+ case LL_IOC_QUOTACTL: {
struct if_quotactl *qctl;
- int cmd, type, id, valid;
OBD_ALLOC_PTR(qctl);
if (!qctl)
if (cfs_copy_from_user(qctl, (void *)arg, sizeof(*qctl)))
GOTO(out_quotactl, rc = -EFAULT);
- cmd = qctl->qc_cmd;
- type = qctl->qc_type;
- id = qctl->qc_id;
- valid = qctl->qc_valid;
-
- switch (cmd) {
- case LUSTRE_Q_INVALIDATE:
- case LUSTRE_Q_FINVALIDATE:
- case Q_QUOTAON:
- case Q_QUOTAOFF:
- case Q_SETQUOTA:
- case Q_SETINFO:
- if (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
- sbi->ll_flags & LL_SBI_RMT_CLIENT)
- GOTO(out_quotactl, rc = -EPERM);
- break;
- case Q_GETQUOTA:
- if (((type == USRQUOTA && cfs_curproc_euid() != id) ||
- (type == GRPQUOTA && !in_egroup_p(id))) &&
- (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
- sbi->ll_flags & LL_SBI_RMT_CLIENT))
- GOTO(out_quotactl, rc = -EPERM);
- break;
- case Q_GETINFO:
- break;
- default:
- CERROR("unsupported quotactl op: %#x\n", cmd);
- GOTO(out_quotactl, rc = -ENOTTY);
- }
-
- if (valid != QC_GENERAL) {
- if (sbi->ll_flags & LL_SBI_RMT_CLIENT)
- GOTO(out_quotactl, rc = -EOPNOTSUPP);
+ rc = quotactl_ioctl(sbi, qctl);
- if (cmd == Q_GETINFO)
- qctl->qc_cmd = Q_GETOINFO;
- else if (cmd == Q_GETQUOTA)
- qctl->qc_cmd = Q_GETOQUOTA;
- else
- GOTO(out_quotactl, rc = -EINVAL);
-
- switch (valid) {
- case QC_MDTIDX:
- rc = obd_iocontrol(OBD_IOC_QUOTACTL,
- sbi->ll_md_exp,
- sizeof(*qctl), qctl, NULL);
- break;
- case QC_OSTIDX:
- rc = obd_iocontrol(OBD_IOC_QUOTACTL,
- sbi->ll_dt_exp,
- sizeof(*qctl), qctl, NULL);
- break;
- case QC_UUID:
- rc = obd_iocontrol(OBD_IOC_QUOTACTL,
- sbi->ll_md_exp,
- sizeof(*qctl), qctl, NULL);
- if (rc == -EAGAIN)
- rc = obd_iocontrol(OBD_IOC_QUOTACTL,
- sbi->ll_dt_exp,
- sizeof(*qctl), qctl,
- NULL);
- break;
- default:
- rc = -EINVAL;
- break;
- }
-
- if (rc)
- GOTO(out_quotactl, rc);
- else
- qctl->qc_cmd = cmd;
- } else {
- struct obd_quotactl *oqctl;
-
- OBD_ALLOC_PTR(oqctl);
- if (!oqctl)
- GOTO(out_quotactl, rc = -ENOMEM);
-
- QCTL_COPY(oqctl, qctl);
- rc = obd_quotactl(sbi->ll_md_exp, oqctl);
- if (rc) {
- if (rc != -EALREADY && cmd == Q_QUOTAON) {
- oqctl->qc_cmd = Q_QUOTAOFF;
- obd_quotactl(sbi->ll_md_exp, oqctl);
- }
- OBD_FREE_PTR(oqctl);
- GOTO(out_quotactl, rc);
- } else {
- QCTL_COPY(qctl, oqctl);
- OBD_FREE_PTR(oqctl);
- }
- }
-
- if (cfs_copy_to_user((void *)arg, qctl, sizeof(*qctl)))
+ if (rc == 0 && cfs_copy_to_user((void *)arg,qctl,sizeof(*qctl)))
rc = -EFAULT;
out_quotactl:
}
#endif
case LL_IOC_GETOBDCOUNT: {
- int count;
+ int count, vallen;
+ struct obd_export *exp;
if (cfs_copy_from_user(&count, (int *)arg, sizeof(int)))
RETURN(-EFAULT);
- if (!count) {
- /* get ost count */
- struct lov_obd *lov = &sbi->ll_dt_exp->exp_obd->u.lov;
- count = lov->desc.ld_tgt_count;
- } else {
- /* get mdt count */
- struct lmv_obd *lmv = &sbi->ll_md_exp->exp_obd->u.lmv;
- count = lmv->desc.ld_tgt_count;
+ /* get ost count when count is zero, get mdt count otherwise */
+ exp = count ? sbi->ll_md_exp : sbi->ll_dt_exp;
+ vallen = sizeof(count);
+ rc = obd_get_info(exp, sizeof(KEY_TGT_COUNT), KEY_TGT_COUNT,
+ &vallen, &count, NULL);
+ if (rc) {
+ CERROR("get target count failed: %d\n", rc);
+ RETURN(rc);
}
if (cfs_copy_to_user((int *)arg, &count, sizeof(int)))
.release = ll_dir_release,
.read = generic_read_dir,
.readdir = ll_readdir,
- .ioctl = ll_dir_ioctl
+ .ioctl = ll_dir_ioctl,
+ .fsync = ll_fsync
};