Whamcloud - gitweb
LU-6838 llog: limit file size of plain logs 28/18028/12
authorAlex Zhuravlev <alexey.zhuravlev@intel.com>
Mon, 18 Jan 2016 06:24:19 +0000 (09:24 +0300)
committerOleg Drokin <oleg.drokin@intel.com>
Sat, 17 Dec 2016 05:35:21 +0000 (05:35 +0000)
on small filesystems plain log can grow dramatically. especially
given large record sizes produced by DNE and extended chunksize.
I saw >50% of space consumed by a single llog file which was still
in use. this leads to test failures (sanityn, etc).
the patch introduces additional limit on plain llog size, which
is calculated as <free space>/64 (128MB at most) at llog creation
time.

Change-Id: I0eab8177d4e416a32a6aab56d47e4142c81d13de
Signed-off-by: Alex Zhuravlev <alexey.zhuravlev@intel.com>
Reviewed-on: https://review.whamcloud.com/18028
Tested-by: Jenkins
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: wangdi <di.wang@intel.com>
Reviewed-by: Mike Pershin <mike.pershin@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
lustre/include/lustre_log.h
lustre/obdclass/llog.c
lustre/obdclass/llog_cat.c
lustre/obdclass/llog_internal.h
lustre/obdclass/llog_osd.c

index 28dcbf2..fe107c7 100644 (file)
@@ -275,6 +275,7 @@ struct llog_handle {
        __u64                    lgh_cur_offset; /* used during llog_process */
        /* used during llog_osd_write_rec */
        __u64                    lgh_write_offset;
+       int                      lgh_max_size;
        struct llog_ctxt        *lgh_ctxt;
        union {
                struct plain_handle_data         phd;
index b378384..f2f2fc6 100644 (file)
@@ -515,8 +515,19 @@ repeat:
                                 * while llog_processing, check this is not
                                 * the case and re-read the current chunk
                                 * otherwise. */
+                               int records;
                                if (index > loghandle->lgh_last_idx)
                                        GOTO(out, rc = 0);
+                               /* <2 records means no more records
+                                * if the last record we processed was
+                                * the final one, then the underlying
+                                * object might have been destroyed yet.
+                                * we better don't access that.. */
+                               mutex_lock(&loghandle->lgh_hdr_mutex);
+                               records = loghandle->lgh_hdr->llh_count;
+                               mutex_unlock(&loghandle->lgh_hdr_mutex);
+                               if (records <= 1)
+                                       GOTO(out, rc = 0);
                                CDEBUG(D_OTHER, "Re-read last llog buffer for "
                                       "new records, index %u, last %u\n",
                                       index, loghandle->lgh_last_idx);
index fd3336b..86a2047 100644 (file)
@@ -171,6 +171,25 @@ static int llog_cat_new_log(const struct lu_env *env,
               POSTID(&cathandle->lgh_id.lgl_oi));
 
        loghandle->lgh_hdr->llh_cat_idx = rec->lid_hdr.lrh_index;
+
+       /* limit max size of plain llog so that space can be
+        * released sooner, especially on small filesystems */
+       /* 2MB for the cases when free space hasn't been learned yet */
+       loghandle->lgh_max_size = 2 << 20;
+       dt = lu2dt_dev(cathandle->lgh_obj->do_lu.lo_dev);
+       rc = dt_statfs(env, dt, &lgi->lgi_statfs);
+       if (rc == 0 && lgi->lgi_statfs.os_bfree > 0) {
+               __u64 freespace = (lgi->lgi_statfs.os_bfree *
+                                 lgi->lgi_statfs.os_bsize) >> 6;
+               if (freespace < loghandle->lgh_max_size)
+                       loghandle->lgh_max_size = freespace;
+               /* shouldn't be > 128MB in any case?
+                * it's 256K records of 512 bytes each */
+               if (freespace > (128 << 20))
+                       loghandle->lgh_max_size = 128 << 20;
+       }
+       rc = 0;
+
 out:
        if (handle != NULL) {
                handle->th_result = rc >= 0 ? 0 : rc;
index e1a7c28..8d5d2ad 100644 (file)
@@ -55,6 +55,7 @@ struct llog_thread_info {
        struct dt_insert_rec             lgi_dt_rec;
        struct lu_seq_range              lgi_range;
        struct llog_cookie               lgi_cookie;
+       struct obd_statfs                lgi_statfs;
        char                             lgi_name[32];
 };
 
index 4fc0b4e..6c3c288 100644 (file)
@@ -558,6 +558,19 @@ static int llog_osd_write_rec(const struct lu_env *env,
        orig_last_idx = loghandle->lgh_last_idx;
        orig_write_offset = loghandle->lgh_write_offset;
        lgi->lgi_off = lgi->lgi_attr.la_size;
+
+       if (loghandle->lgh_max_size > 0 &&
+           lgi->lgi_off >= loghandle->lgh_max_size) {
+               CDEBUG(D_OTHER, "llog is getting too large (%u > %u) at %u "
+                      DOSTID"\n", (unsigned)lgi->lgi_off,
+                      loghandle->lgh_max_size,
+                      (int)loghandle->lgh_last_idx,
+                      POSTID(&loghandle->lgh_id.lgl_oi));
+               /* this is to signal that this llog is full */
+               loghandle->lgh_last_idx = LLOG_HDR_BITMAP_SIZE(llh) - 1;
+               RETURN(-ENOSPC);
+       }
+
        left = chunk_size - (lgi->lgi_off & (chunk_size - 1));
        /* NOTE: padding is a record, but no bit is set */
        if (left != 0 && left != reclen &&