| .. | .. |
|---|
| 5 | 5 | */ |
|---|
| 6 | 6 | #include "xfs.h" |
|---|
| 7 | 7 | #include "xfs_fs.h" |
|---|
| 8 | +#include "xfs_shared.h" |
|---|
| 8 | 9 | #include "xfs_format.h" |
|---|
| 9 | 10 | #include "xfs_log_format.h" |
|---|
| 10 | 11 | #include "xfs_trans_resv.h" |
|---|
| 11 | 12 | #include "xfs_mount.h" |
|---|
| 12 | 13 | #include "xfs_inode.h" |
|---|
| 13 | 14 | #include "xfs_quota.h" |
|---|
| 14 | | -#include "xfs_error.h" |
|---|
| 15 | 15 | #include "xfs_trans.h" |
|---|
| 16 | 16 | #include "xfs_buf_item.h" |
|---|
| 17 | 17 | #include "xfs_trans_priv.h" |
|---|
| .. | .. |
|---|
| 45 | 45 | struct xfs_log_item *lip, |
|---|
| 46 | 46 | struct xfs_log_vec *lv) |
|---|
| 47 | 47 | { |
|---|
| 48 | + struct xfs_disk_dquot ddq; |
|---|
| 48 | 49 | struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip); |
|---|
| 49 | 50 | struct xfs_log_iovec *vecp = NULL; |
|---|
| 50 | 51 | struct xfs_dq_logformat *qlf; |
|---|
| .. | .. |
|---|
| 52 | 53 | qlf = xlog_prepare_iovec(lv, &vecp, XLOG_REG_TYPE_QFORMAT); |
|---|
| 53 | 54 | qlf->qlf_type = XFS_LI_DQUOT; |
|---|
| 54 | 55 | qlf->qlf_size = 2; |
|---|
| 55 | | - qlf->qlf_id = be32_to_cpu(qlip->qli_dquot->q_core.d_id); |
|---|
| 56 | + qlf->qlf_id = qlip->qli_dquot->q_id; |
|---|
| 56 | 57 | qlf->qlf_blkno = qlip->qli_dquot->q_blkno; |
|---|
| 57 | 58 | qlf->qlf_len = 1; |
|---|
| 58 | 59 | qlf->qlf_boffset = qlip->qli_dquot->q_bufoffset; |
|---|
| 59 | 60 | xlog_finish_iovec(lv, vecp, sizeof(struct xfs_dq_logformat)); |
|---|
| 60 | 61 | |
|---|
| 61 | | - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_DQUOT, |
|---|
| 62 | | - &qlip->qli_dquot->q_core, |
|---|
| 62 | + xfs_dquot_to_disk(&ddq, qlip->qli_dquot); |
|---|
| 63 | + |
|---|
| 64 | + xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_DQUOT, &ddq, |
|---|
| 63 | 65 | sizeof(struct xfs_disk_dquot)); |
|---|
| 64 | 66 | } |
|---|
| 65 | 67 | |
|---|
| .. | .. |
|---|
| 94 | 96 | wake_up(&dqp->q_pinwait); |
|---|
| 95 | 97 | } |
|---|
| 96 | 98 | |
|---|
| 97 | | -STATIC xfs_lsn_t |
|---|
| 98 | | -xfs_qm_dquot_logitem_committed( |
|---|
| 99 | | - struct xfs_log_item *lip, |
|---|
| 100 | | - xfs_lsn_t lsn) |
|---|
| 101 | | -{ |
|---|
| 102 | | - /* |
|---|
| 103 | | - * We always re-log the entire dquot when it becomes dirty, |
|---|
| 104 | | - * so, the latest copy _is_ the only one that matters. |
|---|
| 105 | | - */ |
|---|
| 106 | | - return lsn; |
|---|
| 107 | | -} |
|---|
| 108 | | - |
|---|
| 109 | 99 | /* |
|---|
| 110 | 100 | * This is called to wait for the given dquot to be unpinned. |
|---|
| 111 | 101 | * Most of these pin/unpin routines are plagiarized from inode code. |
|---|
| .. | .. |
|---|
| 125 | 115 | wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0)); |
|---|
| 126 | 116 | } |
|---|
| 127 | 117 | |
|---|
| 128 | | -/* |
|---|
| 129 | | - * Callback used to mark a buffer with XFS_LI_FAILED when items in the buffer |
|---|
| 130 | | - * have been failed during writeback |
|---|
| 131 | | - * |
|---|
| 132 | | - * this informs the AIL that the dquot is already flush locked on the next push, |
|---|
| 133 | | - * and acquires a hold on the buffer to ensure that it isn't reclaimed before |
|---|
| 134 | | - * dirty data makes it to disk. |
|---|
| 135 | | - */ |
|---|
| 136 | | -STATIC void |
|---|
| 137 | | -xfs_dquot_item_error( |
|---|
| 138 | | - struct xfs_log_item *lip, |
|---|
| 139 | | - struct xfs_buf *bp) |
|---|
| 140 | | -{ |
|---|
| 141 | | - ASSERT(!completion_done(&DQUOT_ITEM(lip)->qli_dquot->q_flush)); |
|---|
| 142 | | - xfs_set_li_failed(lip, bp); |
|---|
| 143 | | -} |
|---|
| 144 | | - |
|---|
| 145 | 118 | STATIC uint |
|---|
| 146 | 119 | xfs_qm_dquot_logitem_push( |
|---|
| 147 | 120 | struct xfs_log_item *lip, |
|---|
| .. | .. |
|---|
| 156 | 129 | |
|---|
| 157 | 130 | if (atomic_read(&dqp->q_pincount) > 0) |
|---|
| 158 | 131 | return XFS_ITEM_PINNED; |
|---|
| 159 | | - |
|---|
| 160 | | - /* |
|---|
| 161 | | - * The buffer containing this item failed to be written back |
|---|
| 162 | | - * previously. Resubmit the buffer for IO |
|---|
| 163 | | - */ |
|---|
| 164 | | - if (test_bit(XFS_LI_FAILED, &lip->li_flags)) { |
|---|
| 165 | | - if (!xfs_buf_trylock(bp)) |
|---|
| 166 | | - return XFS_ITEM_LOCKED; |
|---|
| 167 | | - |
|---|
| 168 | | - if (!xfs_buf_resubmit_failed_buffers(bp, buffer_list)) |
|---|
| 169 | | - rval = XFS_ITEM_FLUSHING; |
|---|
| 170 | | - |
|---|
| 171 | | - xfs_buf_unlock(bp); |
|---|
| 172 | | - return rval; |
|---|
| 173 | | - } |
|---|
| 174 | 132 | |
|---|
| 175 | 133 | if (!xfs_dqlock_nowait(dqp)) |
|---|
| 176 | 134 | return XFS_ITEM_LOCKED; |
|---|
| .. | .. |
|---|
| 201 | 159 | if (!xfs_buf_delwri_queue(bp, buffer_list)) |
|---|
| 202 | 160 | rval = XFS_ITEM_FLUSHING; |
|---|
| 203 | 161 | xfs_buf_relse(bp); |
|---|
| 204 | | - } |
|---|
| 162 | + } else if (error == -EAGAIN) |
|---|
| 163 | + rval = XFS_ITEM_LOCKED; |
|---|
| 205 | 164 | |
|---|
| 206 | 165 | spin_lock(&lip->li_ailp->ail_lock); |
|---|
| 207 | 166 | out_unlock: |
|---|
| .. | .. |
|---|
| 209 | 168 | return rval; |
|---|
| 210 | 169 | } |
|---|
| 211 | 170 | |
|---|
| 212 | | -/* |
|---|
| 213 | | - * Unlock the dquot associated with the log item. |
|---|
| 214 | | - * Clear the fields of the dquot and dquot log item that |
|---|
| 215 | | - * are specific to the current transaction. If the |
|---|
| 216 | | - * hold flags is set, do not unlock the dquot. |
|---|
| 217 | | - */ |
|---|
| 218 | 171 | STATIC void |
|---|
| 219 | | -xfs_qm_dquot_logitem_unlock( |
|---|
| 172 | +xfs_qm_dquot_logitem_release( |
|---|
| 220 | 173 | struct xfs_log_item *lip) |
|---|
| 221 | 174 | { |
|---|
| 222 | 175 | struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; |
|---|
| 223 | 176 | |
|---|
| 224 | 177 | ASSERT(XFS_DQ_IS_LOCKED(dqp)); |
|---|
| 225 | | - |
|---|
| 226 | | - /* |
|---|
| 227 | | - * Clear the transaction pointer in the dquot |
|---|
| 228 | | - */ |
|---|
| 229 | | - dqp->q_transp = NULL; |
|---|
| 230 | 178 | |
|---|
| 231 | 179 | /* |
|---|
| 232 | 180 | * dquots are never 'held' from getting unlocked at the end of |
|---|
| .. | .. |
|---|
| 237 | 185 | xfs_dqunlock(dqp); |
|---|
| 238 | 186 | } |
|---|
| 239 | 187 | |
|---|
| 240 | | -/* |
|---|
| 241 | | - * this needs to stamp an lsn into the dquot, I think. |
|---|
| 242 | | - * rpc's that look at user dquot's would then have to |
|---|
| 243 | | - * push on the dependency recorded in the dquot |
|---|
| 244 | | - */ |
|---|
| 245 | 188 | STATIC void |
|---|
| 246 | 189 | xfs_qm_dquot_logitem_committing( |
|---|
| 247 | 190 | struct xfs_log_item *lip, |
|---|
| 248 | | - xfs_lsn_t lsn) |
|---|
| 191 | + xfs_csn_t seq) |
|---|
| 249 | 192 | { |
|---|
| 193 | + return xfs_qm_dquot_logitem_release(lip); |
|---|
| 250 | 194 | } |
|---|
| 251 | 195 | |
|---|
| 252 | | -/* |
|---|
| 253 | | - * This is the ops vector for dquots |
|---|
| 254 | | - */ |
|---|
| 255 | 196 | static const struct xfs_item_ops xfs_dquot_item_ops = { |
|---|
| 256 | 197 | .iop_size = xfs_qm_dquot_logitem_size, |
|---|
| 257 | 198 | .iop_format = xfs_qm_dquot_logitem_format, |
|---|
| 258 | 199 | .iop_pin = xfs_qm_dquot_logitem_pin, |
|---|
| 259 | 200 | .iop_unpin = xfs_qm_dquot_logitem_unpin, |
|---|
| 260 | | - .iop_unlock = xfs_qm_dquot_logitem_unlock, |
|---|
| 261 | | - .iop_committed = xfs_qm_dquot_logitem_committed, |
|---|
| 201 | + .iop_release = xfs_qm_dquot_logitem_release, |
|---|
| 202 | + .iop_committing = xfs_qm_dquot_logitem_committing, |
|---|
| 262 | 203 | .iop_push = xfs_qm_dquot_logitem_push, |
|---|
| 263 | | - .iop_committing = xfs_qm_dquot_logitem_committing, |
|---|
| 264 | | - .iop_error = xfs_dquot_item_error |
|---|
| 265 | 204 | }; |
|---|
| 266 | 205 | |
|---|
| 267 | 206 | /* |
|---|
| .. | .. |
|---|
| 320 | 259 | } |
|---|
| 321 | 260 | |
|---|
| 322 | 261 | /* |
|---|
| 323 | | - * Pinning has no meaning for an quotaoff item, so just return. |
|---|
| 324 | | - */ |
|---|
| 325 | | -STATIC void |
|---|
| 326 | | -xfs_qm_qoff_logitem_pin( |
|---|
| 327 | | - struct xfs_log_item *lip) |
|---|
| 328 | | -{ |
|---|
| 329 | | -} |
|---|
| 330 | | - |
|---|
| 331 | | -/* |
|---|
| 332 | | - * Since pinning has no meaning for an quotaoff item, unpinning does |
|---|
| 333 | | - * not either. |
|---|
| 334 | | - */ |
|---|
| 335 | | -STATIC void |
|---|
| 336 | | -xfs_qm_qoff_logitem_unpin( |
|---|
| 337 | | - struct xfs_log_item *lip, |
|---|
| 338 | | - int remove) |
|---|
| 339 | | -{ |
|---|
| 340 | | -} |
|---|
| 341 | | - |
|---|
| 342 | | -/* |
|---|
| 343 | 262 | * There isn't much you can do to push a quotaoff item. It is simply |
|---|
| 344 | 263 | * stuck waiting for the log to be flushed to disk. |
|---|
| 345 | 264 | */ |
|---|
| .. | .. |
|---|
| 351 | 270 | return XFS_ITEM_LOCKED; |
|---|
| 352 | 271 | } |
|---|
| 353 | 272 | |
|---|
| 354 | | -/* |
|---|
| 355 | | - * Quotaoff items have no locking or pushing, so return failure |
|---|
| 356 | | - * so that the caller doesn't bother with us. |
|---|
| 357 | | - */ |
|---|
| 358 | | -STATIC void |
|---|
| 359 | | -xfs_qm_qoff_logitem_unlock( |
|---|
| 360 | | - struct xfs_log_item *lip) |
|---|
| 361 | | -{ |
|---|
| 362 | | -} |
|---|
| 363 | | - |
|---|
| 364 | | -/* |
|---|
| 365 | | - * The quotaoff-start-item is logged only once and cannot be moved in the log, |
|---|
| 366 | | - * so simply return the lsn at which it's been logged. |
|---|
| 367 | | - */ |
|---|
| 368 | | -STATIC xfs_lsn_t |
|---|
| 369 | | -xfs_qm_qoff_logitem_committed( |
|---|
| 370 | | - struct xfs_log_item *lip, |
|---|
| 371 | | - xfs_lsn_t lsn) |
|---|
| 372 | | -{ |
|---|
| 373 | | - return lsn; |
|---|
| 374 | | -} |
|---|
| 375 | | - |
|---|
| 376 | 273 | STATIC xfs_lsn_t |
|---|
| 377 | 274 | xfs_qm_qoffend_logitem_committed( |
|---|
| 378 | 275 | struct xfs_log_item *lip, |
|---|
| .. | .. |
|---|
| 380 | 277 | { |
|---|
| 381 | 278 | struct xfs_qoff_logitem *qfe = QOFF_ITEM(lip); |
|---|
| 382 | 279 | struct xfs_qoff_logitem *qfs = qfe->qql_start_lip; |
|---|
| 383 | | - struct xfs_ail *ailp = qfs->qql_item.li_ailp; |
|---|
| 384 | 280 | |
|---|
| 385 | | - /* |
|---|
| 386 | | - * Delete the qoff-start logitem from the AIL. |
|---|
| 387 | | - * xfs_trans_ail_delete() drops the AIL lock. |
|---|
| 388 | | - */ |
|---|
| 389 | | - spin_lock(&ailp->ail_lock); |
|---|
| 390 | | - xfs_trans_ail_delete(ailp, &qfs->qql_item, SHUTDOWN_LOG_IO_ERROR); |
|---|
| 281 | + xfs_qm_qoff_logitem_relse(qfs); |
|---|
| 391 | 282 | |
|---|
| 392 | | - kmem_free(qfs->qql_item.li_lv_shadow); |
|---|
| 393 | 283 | kmem_free(lip->li_lv_shadow); |
|---|
| 394 | | - kmem_free(qfs); |
|---|
| 395 | 284 | kmem_free(qfe); |
|---|
| 396 | 285 | return (xfs_lsn_t)-1; |
|---|
| 397 | 286 | } |
|---|
| 398 | 287 | |
|---|
| 399 | | -/* |
|---|
| 400 | | - * XXX rcc - don't know quite what to do with this. I think we can |
|---|
| 401 | | - * just ignore it. The only time that isn't the case is if we allow |
|---|
| 402 | | - * the client to somehow see that quotas have been turned off in which |
|---|
| 403 | | - * we can't allow that to get back until the quotaoff hits the disk. |
|---|
| 404 | | - * So how would that happen? Also, do we need different routines for |
|---|
| 405 | | - * quotaoff start and quotaoff end? I suspect the answer is yes but |
|---|
| 406 | | - * to be sure, I need to look at the recovery code and see how quota off |
|---|
| 407 | | - * recovery is handled (do we roll forward or back or do something else). |
|---|
| 408 | | - * If we roll forwards or backwards, then we need two separate routines, |
|---|
| 409 | | - * one that does nothing and one that stamps in the lsn that matters |
|---|
| 410 | | - * (truly makes the quotaoff irrevocable). If we do something else, |
|---|
| 411 | | - * then maybe we don't need two. |
|---|
| 412 | | - */ |
|---|
| 413 | 288 | STATIC void |
|---|
| 414 | | -xfs_qm_qoff_logitem_committing( |
|---|
| 415 | | - struct xfs_log_item *lip, |
|---|
| 416 | | - xfs_lsn_t commit_lsn) |
|---|
| 289 | +xfs_qm_qoff_logitem_release( |
|---|
| 290 | + struct xfs_log_item *lip) |
|---|
| 417 | 291 | { |
|---|
| 292 | + struct xfs_qoff_logitem *qoff = QOFF_ITEM(lip); |
|---|
| 293 | + |
|---|
| 294 | + if (test_bit(XFS_LI_ABORTED, &lip->li_flags)) { |
|---|
| 295 | + if (qoff->qql_start_lip) |
|---|
| 296 | + xfs_qm_qoff_logitem_relse(qoff->qql_start_lip); |
|---|
| 297 | + xfs_qm_qoff_logitem_relse(qoff); |
|---|
| 298 | + } |
|---|
| 418 | 299 | } |
|---|
| 419 | 300 | |
|---|
| 420 | 301 | static const struct xfs_item_ops xfs_qm_qoffend_logitem_ops = { |
|---|
| 421 | 302 | .iop_size = xfs_qm_qoff_logitem_size, |
|---|
| 422 | 303 | .iop_format = xfs_qm_qoff_logitem_format, |
|---|
| 423 | | - .iop_pin = xfs_qm_qoff_logitem_pin, |
|---|
| 424 | | - .iop_unpin = xfs_qm_qoff_logitem_unpin, |
|---|
| 425 | | - .iop_unlock = xfs_qm_qoff_logitem_unlock, |
|---|
| 426 | 304 | .iop_committed = xfs_qm_qoffend_logitem_committed, |
|---|
| 427 | 305 | .iop_push = xfs_qm_qoff_logitem_push, |
|---|
| 428 | | - .iop_committing = xfs_qm_qoff_logitem_committing |
|---|
| 306 | + .iop_release = xfs_qm_qoff_logitem_release, |
|---|
| 429 | 307 | }; |
|---|
| 430 | 308 | |
|---|
| 431 | | -/* |
|---|
| 432 | | - * This is the ops vector shared by all quotaoff-start log items. |
|---|
| 433 | | - */ |
|---|
| 434 | 309 | static const struct xfs_item_ops xfs_qm_qoff_logitem_ops = { |
|---|
| 435 | 310 | .iop_size = xfs_qm_qoff_logitem_size, |
|---|
| 436 | 311 | .iop_format = xfs_qm_qoff_logitem_format, |
|---|
| 437 | | - .iop_pin = xfs_qm_qoff_logitem_pin, |
|---|
| 438 | | - .iop_unpin = xfs_qm_qoff_logitem_unpin, |
|---|
| 439 | | - .iop_unlock = xfs_qm_qoff_logitem_unlock, |
|---|
| 440 | | - .iop_committed = xfs_qm_qoff_logitem_committed, |
|---|
| 441 | 312 | .iop_push = xfs_qm_qoff_logitem_push, |
|---|
| 442 | | - .iop_committing = xfs_qm_qoff_logitem_committing |
|---|
| 313 | + .iop_release = xfs_qm_qoff_logitem_release, |
|---|
| 443 | 314 | }; |
|---|
| 315 | + |
|---|
| 316 | +/* |
|---|
| 317 | + * Delete the quotaoff intent from the AIL and free it. On success, |
|---|
| 318 | + * this should only be called for the start item. It can be used for |
|---|
| 319 | + * either on shutdown or abort. |
|---|
| 320 | + */ |
|---|
| 321 | +void |
|---|
| 322 | +xfs_qm_qoff_logitem_relse( |
|---|
| 323 | + struct xfs_qoff_logitem *qoff) |
|---|
| 324 | +{ |
|---|
| 325 | + struct xfs_log_item *lip = &qoff->qql_item; |
|---|
| 326 | + |
|---|
| 327 | + ASSERT(test_bit(XFS_LI_IN_AIL, &lip->li_flags) || |
|---|
| 328 | + test_bit(XFS_LI_ABORTED, &lip->li_flags) || |
|---|
| 329 | + XFS_FORCED_SHUTDOWN(lip->li_mountp)); |
|---|
| 330 | + xfs_trans_ail_delete(lip, 0); |
|---|
| 331 | + kmem_free(lip->li_lv_shadow); |
|---|
| 332 | + kmem_free(qoff); |
|---|
| 333 | +} |
|---|
| 444 | 334 | |
|---|
| 445 | 335 | /* |
|---|
| 446 | 336 | * Allocate and initialize an quotaoff item of the correct quota type(s). |
|---|
| .. | .. |
|---|
| 453 | 343 | { |
|---|
| 454 | 344 | struct xfs_qoff_logitem *qf; |
|---|
| 455 | 345 | |
|---|
| 456 | | - qf = kmem_zalloc(sizeof(struct xfs_qoff_logitem), KM_SLEEP); |
|---|
| 346 | + qf = kmem_zalloc(sizeof(struct xfs_qoff_logitem), 0); |
|---|
| 457 | 347 | |
|---|
| 458 | 348 | xfs_log_item_init(mp, &qf->qql_item, XFS_LI_QUOTAOFF, start ? |
|---|
| 459 | 349 | &xfs_qm_qoffend_logitem_ops : &xfs_qm_qoff_logitem_ops); |
|---|